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

Side by Side Diff: content/browser/renderer_host/browser_render_process_host.cc

Issue 8515027: Define the public version of the browser side RenderProcessHost interface. This interface is not ... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 1 month 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) 2011 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 // Represents the browser side of the browser <--> renderer communication
6 // channel. There will be one RenderProcessHost per renderer process.
7
8 #include "content/browser/renderer_host/browser_render_process_host.h"
9
10 #include <algorithm>
11 #include <limits>
12 #include <vector>
13
14 #if defined(OS_POSIX)
15 #include <utility> // for pair<>
16 #endif
17
18 #include "base/base_switches.h"
19 #include "base/bind.h"
20 #include "base/bind_helpers.h"
21 #include "base/callback.h"
22 #include "base/command_line.h"
23 #include "base/logging.h"
24 #include "base/metrics/field_trial.h"
25 #include "base/metrics/histogram.h"
26 #include "base/path_service.h"
27 #include "base/platform_file.h"
28 #include "base/stl_util.h"
29 #include "base/string_util.h"
30 #include "base/threading/thread.h"
31 #include "base/threading/thread_restrictions.h"
32 #include "content/browser/appcache/appcache_dispatcher_host.h"
33 #include "content/browser/browser_child_process_host.h"
34 #include "content/browser/browser_context.h"
35 #include "content/browser/child_process_security_policy.h"
36 #include "content/browser/device_orientation/message_filter.h"
37 #include "content/browser/download/mhtml_generation_manager.h"
38 #include "content/browser/file_system/file_system_dispatcher_host.h"
39 #include "content/browser/geolocation/geolocation_dispatcher_host.h"
40 #include "content/browser/gpu/gpu_data_manager.h"
41 #include "content/browser/gpu/gpu_process_host.h"
42 #include "content/browser/in_process_webkit/dom_storage_message_filter.h"
43 #include "content/browser/in_process_webkit/indexed_db_dispatcher_host.h"
44 #include "content/browser/mime_registry_message_filter.h"
45 #include "content/browser/plugin_service.h"
46 #include "content/browser/renderer_host/blob_message_filter.h"
47 #include "content/browser/renderer_host/clipboard_message_filter.h"
48 #include "content/browser/renderer_host/database_message_filter.h"
49 #include "content/browser/renderer_host/file_utilities_message_filter.h"
50 #include "content/browser/renderer_host/gpu_message_filter.h"
51 #include "content/browser/renderer_host/media/audio_input_renderer_host.h"
52 #include "content/browser/renderer_host/media/audio_renderer_host.h"
53 #include "content/browser/renderer_host/media/media_stream_dispatcher_host.h"
54 #include "content/browser/renderer_host/media/video_capture_host.h"
55 #include "content/browser/renderer_host/p2p/socket_dispatcher_host.h"
56 #include "content/browser/renderer_host/pepper_file_message_filter.h"
57 #include "content/browser/renderer_host/pepper_message_filter.h"
58 #include "content/browser/renderer_host/quota_dispatcher_host.h"
59 #include "content/browser/renderer_host/render_message_filter.h"
60 #include "content/browser/renderer_host/render_view_host.h"
61 #include "content/browser/renderer_host/render_view_host_delegate.h"
62 #include "content/browser/renderer_host/render_widget_helper.h"
63 #include "content/browser/renderer_host/render_widget_host.h"
64 #include "content/browser/renderer_host/resource_message_filter.h"
65 #include "content/browser/renderer_host/socket_stream_dispatcher_host.h"
66 #include "content/browser/renderer_host/text_input_client_message_filter.h"
67 #include "content/browser/resolve_proxy_msg_helper.h"
68 #include "content/browser/speech/speech_input_dispatcher_host.h"
69 #include "content/browser/trace_message_filter.h"
70 #include "content/browser/user_metrics.h"
71 #include "content/browser/worker_host/worker_message_filter.h"
72 #include "content/common/child_process_info.h"
73 #include "content/common/child_process_messages.h"
74 #include "content/common/gpu/gpu_messages.h"
75 #include "content/public/browser/notification_service.h"
76 #include "content/common/process_watcher.h"
77 #include "content/common/resource_messages.h"
78 #include "content/common/view_messages.h"
79 #include "content/public/browser/content_browser_client.h"
80 #include "content/public/common/content_switches.h"
81 #include "content/public/common/result_codes.h"
82 #include "content/renderer/render_process_impl.h"
83 #include "content/renderer/render_thread_impl.h"
84 #include "ipc/ipc_logging.h"
85 #include "ipc/ipc_platform_file.h"
86 #include "ipc/ipc_switches.h"
87 #include "media/base/media_switches.h"
88 #include "net/url_request/url_request_context_getter.h"
89 #include "ui/base/ui_base_switches.h"
90 #include "ui/gfx/gl/gl_switches.h"
91 #include "webkit/fileapi/file_system_path_manager.h"
92 #include "webkit/fileapi/sandbox_mount_point_provider.h"
93 #include "webkit/glue/resource_type.h"
94 #include "webkit/plugins/plugin_switches.h"
95
96 #if defined(OS_WIN)
97 #include <objbase.h>
98 #include "base/synchronization/waitable_event.h"
99 #include "content/common/section_util_win.h"
100 #endif
101
102 #include "third_party/skia/include/core/SkBitmap.h"
103
104 using content::BrowserThread;
105
106 // This class creates the IO thread for the renderer when running in
107 // single-process mode. It's not used in multi-process mode.
108 class RendererMainThread : public base::Thread {
109 public:
110 explicit RendererMainThread(const std::string& channel_id)
111 : base::Thread("Chrome_InProcRendererThread"),
112 channel_id_(channel_id),
113 render_process_(NULL) {
114 }
115
116 ~RendererMainThread() {
117 Stop();
118 }
119
120 protected:
121 virtual void Init() {
122 #if defined(OS_WIN)
123 CoInitialize(NULL);
124 #endif
125
126 render_process_ = new RenderProcessImpl();
127 render_process_->set_main_thread(new RenderThreadImpl(channel_id_));
128 }
129
130 virtual void CleanUp() {
131 delete render_process_;
132
133 #if defined(OS_WIN)
134 CoUninitialize();
135 #endif
136 // It's a little lame to manually set this flag. But the single process
137 // RendererThread will receive the WM_QUIT. We don't need to assert on
138 // this thread, so just force the flag manually.
139 // If we want to avoid this, we could create the InProcRendererThread
140 // directly with _beginthreadex() rather than using the Thread class.
141 // We used to set this flag in the Init function above. However there
142 // other threads like WebThread which are created by this thread
143 // which resets this flag. Please see Thread::StartWithOptions. Setting
144 // this flag to true in Cleanup works around these problems.
145 base::Thread::SetThreadWasQuitProperly(true);
146 }
147
148 private:
149 std::string channel_id_;
150 // Deleted in CleanUp() on the renderer thread, so don't use a smart pointer.
151 RenderProcess* render_process_;
152 };
153
154 namespace {
155
156 // Helper class that we pass to ResourceMessageFilter so that it can find the
157 // right net::URLRequestContext for a request.
158 class RendererURLRequestContextSelector
159 : public ResourceMessageFilter::URLRequestContextSelector {
160 public:
161 RendererURLRequestContextSelector(content::BrowserContext* browser_context,
162 int render_child_id)
163 : request_context_(browser_context->GetRequestContextForRenderProcess(
164 render_child_id)),
165 media_request_context_(browser_context->GetRequestContextForMedia()) {
166 }
167
168 virtual net::URLRequestContext* GetRequestContext(
169 ResourceType::Type resource_type) {
170 net::URLRequestContextGetter* request_context = request_context_;
171 // If the request has resource type of ResourceType::MEDIA, we use a request
172 // context specific to media for handling it because these resources have
173 // specific needs for caching.
174 if (resource_type == ResourceType::MEDIA)
175 request_context = media_request_context_;
176 return request_context->GetURLRequestContext();
177 }
178
179 private:
180 virtual ~RendererURLRequestContextSelector() {}
181
182 scoped_refptr<net::URLRequestContextGetter> request_context_;
183 scoped_refptr<net::URLRequestContextGetter> media_request_context_;
184 };
185
186 } // namespace
187
188 BrowserRenderProcessHost::BrowserRenderProcessHost(
189 content::BrowserContext* browser_context)
190 : RenderProcessHost(browser_context),
191 visible_widgets_(0),
192 backgrounded_(true),
193 ALLOW_THIS_IN_INITIALIZER_LIST(cached_dibs_cleaner_(
194 FROM_HERE, base::TimeDelta::FromSeconds(5),
195 this, &BrowserRenderProcessHost::ClearTransportDIBCache)),
196 accessibility_enabled_(false),
197 is_initialized_(false) {
198 widget_helper_ = new RenderWidgetHelper();
199
200 ChildProcessSecurityPolicy::GetInstance()->Add(id());
201
202 // Grant most file permissions to this renderer.
203 // PLATFORM_FILE_TEMPORARY, PLATFORM_FILE_HIDDEN and
204 // PLATFORM_FILE_DELETE_ON_CLOSE are not granted, because no existing API
205 // requests them.
206 // This is for the filesystem sandbox.
207 ChildProcessSecurityPolicy::GetInstance()->GrantPermissionsForFile(
208 id(), browser_context->GetPath().Append(
209 fileapi::SandboxMountPointProvider::kNewFileSystemDirectory),
210 base::PLATFORM_FILE_OPEN |
211 base::PLATFORM_FILE_CREATE |
212 base::PLATFORM_FILE_OPEN_ALWAYS |
213 base::PLATFORM_FILE_CREATE_ALWAYS |
214 base::PLATFORM_FILE_OPEN_TRUNCATED |
215 base::PLATFORM_FILE_READ |
216 base::PLATFORM_FILE_WRITE |
217 base::PLATFORM_FILE_EXCLUSIVE_READ |
218 base::PLATFORM_FILE_EXCLUSIVE_WRITE |
219 base::PLATFORM_FILE_ASYNC |
220 base::PLATFORM_FILE_WRITE_ATTRIBUTES |
221 base::PLATFORM_FILE_ENUMERATE);
222 // This is so that we can read and move stuff out of the old filesystem
223 // sandbox.
224 ChildProcessSecurityPolicy::GetInstance()->GrantPermissionsForFile(
225 id(), browser_context->GetPath().Append(
226 fileapi::SandboxMountPointProvider::kOldFileSystemDirectory),
227 base::PLATFORM_FILE_READ | base::PLATFORM_FILE_WRITE |
228 base::PLATFORM_FILE_WRITE_ATTRIBUTES | base::PLATFORM_FILE_ENUMERATE);
229 // This is so that we can rename the old sandbox out of the way so that we
230 // know we've taken care of it.
231 ChildProcessSecurityPolicy::GetInstance()->GrantPermissionsForFile(
232 id(), browser_context->GetPath().Append(
233 fileapi::SandboxMountPointProvider::kRenamedOldFileSystemDirectory),
234 base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_CREATE_ALWAYS |
235 base::PLATFORM_FILE_WRITE);
236
237 // Note: When we create the BrowserRenderProcessHost, it's technically
238 // backgrounded, because it has no visible listeners. But the process
239 // doesn't actually exist yet, so we'll Background it later, after
240 // creation.
241 }
242
243 BrowserRenderProcessHost::~BrowserRenderProcessHost() {
244 ChildProcessSecurityPolicy::GetInstance()->Remove(id());
245
246 // We may have some unsent messages at this point, but that's OK.
247 channel_.reset();
248 while (!queued_messages_.empty()) {
249 delete queued_messages_.front();
250 queued_messages_.pop();
251 }
252
253 ClearTransportDIBCache();
254 }
255
256 void BrowserRenderProcessHost::EnableSendQueue() {
257 is_initialized_ = false;
258 }
259
260 bool BrowserRenderProcessHost::Init(bool is_accessibility_enabled) {
261 // calling Init() more than once does nothing, this makes it more convenient
262 // for the view host which may not be sure in some cases
263 if (channel_.get())
264 return true;
265
266 accessibility_enabled_ = is_accessibility_enabled;
267
268 CommandLine::StringType renderer_prefix;
269 #if defined(OS_POSIX)
270 // A command prefix is something prepended to the command line of the spawned
271 // process. It is supported only on POSIX systems.
272 const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
273 renderer_prefix =
274 browser_command_line.GetSwitchValueNative(switches::kRendererCmdPrefix);
275 #endif // defined(OS_POSIX)
276
277 #if defined(OS_LINUX)
278 int flags = renderer_prefix.empty() ? ChildProcessHost::CHILD_ALLOW_SELF :
279 ChildProcessHost::CHILD_NORMAL;
280 #else
281 int flags = ChildProcessHost::CHILD_NORMAL;
282 #endif
283
284 // Find the renderer before creating the channel so if this fails early we
285 // return without creating the channel.
286 FilePath renderer_path = ChildProcessHost::GetChildPath(flags);
287 if (renderer_path.empty())
288 return false;
289
290 // Setup the IPC channel.
291 const std::string channel_id =
292 ChildProcessInfo::GenerateRandomChannelID(this);
293 channel_.reset(new IPC::ChannelProxy(
294 channel_id, IPC::Channel::MODE_SERVER, this,
295 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO)));
296
297 // Call the embedder first so that their IPC filters have priority.
298 content::GetContentClient()->browser()->BrowserRenderProcessHostCreated(this);
299
300 CreateMessageFilters();
301
302 if (run_renderer_in_process()) {
303 // Crank up a thread and run the initialization there. With the way that
304 // messages flow between the browser and renderer, this thread is required
305 // to prevent a deadlock in single-process mode. Since the primordial
306 // thread in the renderer process runs the WebKit code and can sometimes
307 // make blocking calls to the UI thread (i.e. this thread), they need to run
308 // on separate threads.
309 in_process_renderer_.reset(new RendererMainThread(channel_id));
310
311 base::Thread::Options options;
312 #if !defined(TOOLKIT_USES_GTK)
313 // In-process plugins require this to be a UI message loop.
314 options.message_loop_type = MessageLoop::TYPE_UI;
315 #else
316 // We can't have multiple UI loops on GTK, so we don't support
317 // in-process plugins.
318 options.message_loop_type = MessageLoop::TYPE_DEFAULT;
319 #endif
320 in_process_renderer_->StartWithOptions(options);
321
322 OnProcessLaunched(); // Fake a callback that the process is ready.
323 } else {
324 // Build command line for renderer. We call AppendRendererCommandLine()
325 // first so the process type argument will appear first.
326 CommandLine* cmd_line = new CommandLine(renderer_path);
327 if (!renderer_prefix.empty())
328 cmd_line->PrependWrapper(renderer_prefix);
329 AppendRendererCommandLine(cmd_line);
330 cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id);
331
332 // Spawn the child process asynchronously to avoid blocking the UI thread.
333 // As long as there's no renderer prefix, we can use the zygote process
334 // at this stage.
335 child_process_launcher_.reset(new ChildProcessLauncher(
336 #if defined(OS_WIN)
337 FilePath(),
338 #elif defined(OS_POSIX)
339 renderer_prefix.empty(),
340 base::environment_vector(),
341 channel_->TakeClientFileDescriptor(),
342 #endif
343 cmd_line,
344 this));
345
346 fast_shutdown_started_ = false;
347 }
348
349 is_initialized_ = true;
350 return true;
351 }
352
353 void BrowserRenderProcessHost::CreateMessageFilters() {
354 scoped_refptr<RenderMessageFilter> render_message_filter(
355 new RenderMessageFilter(
356 id(),
357 PluginService::GetInstance(),
358 browser_context(),
359 browser_context()->GetRequestContextForRenderProcess(id()),
360 widget_helper_));
361 channel_->AddFilter(render_message_filter);
362
363 ResourceMessageFilter* resource_message_filter = new ResourceMessageFilter(
364 id(), ChildProcessInfo::RENDER_PROCESS,
365 &browser_context()->GetResourceContext(),
366 new RendererURLRequestContextSelector(browser_context(), id()),
367 content::GetContentClient()->browser()->GetResourceDispatcherHost());
368
369 channel_->AddFilter(resource_message_filter);
370 channel_->AddFilter(new AudioInputRendererHost(
371 &browser_context()->GetResourceContext()));
372 channel_->AddFilter(
373 new AudioRendererHost(&browser_context()->GetResourceContext()));
374 channel_->AddFilter(
375 new VideoCaptureHost(&browser_context()->GetResourceContext()));
376 channel_->AddFilter(
377 new AppCacheDispatcherHost(browser_context()->GetAppCacheService(),
378 id()));
379 channel_->AddFilter(new ClipboardMessageFilter());
380 channel_->AddFilter(
381 new DOMStorageMessageFilter(id(), browser_context()->GetWebKitContext()));
382 channel_->AddFilter(
383 new IndexedDBDispatcherHost(id(), browser_context()->GetWebKitContext()));
384 channel_->AddFilter(
385 GeolocationDispatcherHost::New(
386 id(), browser_context()->GetGeolocationPermissionContext()));
387 channel_->AddFilter(new GpuMessageFilter(id(), widget_helper_.get()));
388 channel_->AddFilter(new media_stream::MediaStreamDispatcherHost(
389 &browser_context()->GetResourceContext(), id()));
390 channel_->AddFilter(new PepperFileMessageFilter(id(), browser_context()));
391 channel_->AddFilter(
392 new PepperMessageFilter(&browser_context()->GetResourceContext()));
393 channel_->AddFilter(new speech_input::SpeechInputDispatcherHost(
394 id(), browser_context()->GetRequestContext(),
395 browser_context()->GetSpeechInputPreferences()));
396 channel_->AddFilter(
397 new FileSystemDispatcherHost(browser_context()->GetRequestContext(),
398 browser_context()->GetFileSystemContext()));
399 channel_->AddFilter(new device_orientation::MessageFilter());
400 channel_->AddFilter(
401 new BlobMessageFilter(id(), browser_context()->GetBlobStorageContext()));
402 channel_->AddFilter(new FileUtilitiesMessageFilter(id()));
403 channel_->AddFilter(new MimeRegistryMessageFilter());
404 channel_->AddFilter(new DatabaseMessageFilter(
405 browser_context()->GetDatabaseTracker()));
406 #if defined(OS_MACOSX)
407 channel_->AddFilter(new TextInputClientMessageFilter(id()));
408 #endif
409
410 SocketStreamDispatcherHost* socket_stream_dispatcher_host =
411 new SocketStreamDispatcherHost(
412 new RendererURLRequestContextSelector(browser_context(), id()),
413 &browser_context()->GetResourceContext());
414 channel_->AddFilter(socket_stream_dispatcher_host);
415
416 channel_->AddFilter(
417 new WorkerMessageFilter(
418 id(),
419 &browser_context()->GetResourceContext(),
420 content::GetContentClient()->browser()->GetResourceDispatcherHost(),
421 base::Bind(&RenderWidgetHelper::GetNextRoutingID,
422 base::Unretained(widget_helper_.get()))));
423
424 #if defined(ENABLE_P2P_APIS)
425 channel_->AddFilter(new content::P2PSocketDispatcherHost(
426 &browser_context()->GetResourceContext()));
427 #endif
428
429 channel_->AddFilter(new TraceMessageFilter());
430 channel_->AddFilter(new ResolveProxyMsgHelper(
431 browser_context()->GetRequestContextForRenderProcess(id())));
432 channel_->AddFilter(new QuotaDispatcherHost(
433 id(), browser_context()->GetQuotaManager(),
434 content::GetContentClient()->browser()->CreateQuotaPermissionContext()));
435 }
436
437 int BrowserRenderProcessHost::GetNextRoutingID() {
438 return widget_helper_->GetNextRoutingID();
439 }
440
441 void BrowserRenderProcessHost::UpdateAndSendMaxPageID(int32 page_id) {
442 if (page_id > max_page_id_)
443 Send(new ViewMsg_SetNextPageID(page_id + 1));
444 UpdateMaxPageID(page_id);
445 }
446
447 void BrowserRenderProcessHost::CancelResourceRequests(int render_widget_id) {
448 widget_helper_->CancelResourceRequests(render_widget_id);
449 }
450
451 void BrowserRenderProcessHost::CrossSiteSwapOutACK(
452 const ViewMsg_SwapOut_Params& params) {
453 widget_helper_->CrossSiteSwapOutACK(params);
454 }
455
456 bool BrowserRenderProcessHost::WaitForUpdateMsg(
457 int render_widget_id,
458 const base::TimeDelta& max_delay,
459 IPC::Message* msg) {
460 // The post task to this thread with the process id could be in queue, and we
461 // don't want to dispatch a message before then since it will need the handle.
462 if (child_process_launcher_.get() && child_process_launcher_->IsStarting())
463 return false;
464
465 return widget_helper_->WaitForUpdateMsg(render_widget_id, max_delay, msg);
466 }
467
468 void BrowserRenderProcessHost::ReceivedBadMessage() {
469 if (run_renderer_in_process()) {
470 // In single process mode it is better if we don't suicide but just
471 // crash.
472 CHECK(false);
473 }
474 NOTREACHED();
475 base::KillProcess(GetHandle(), content::RESULT_CODE_KILLED_BAD_MESSAGE,
476 false);
477 }
478
479 void BrowserRenderProcessHost::WidgetRestored() {
480 // Verify we were properly backgrounded.
481 DCHECK_EQ(backgrounded_, (visible_widgets_ == 0));
482 visible_widgets_++;
483 SetBackgrounded(false);
484 }
485
486 void BrowserRenderProcessHost::WidgetHidden() {
487 // On startup, the browser will call Hide
488 if (backgrounded_)
489 return;
490
491 DCHECK_EQ(backgrounded_, (visible_widgets_ == 0));
492 visible_widgets_--;
493 DCHECK_GE(visible_widgets_, 0);
494 if (visible_widgets_ == 0) {
495 DCHECK(!backgrounded_);
496 SetBackgrounded(true);
497 }
498 }
499
500 int BrowserRenderProcessHost::VisibleWidgetCount() const {
501 return visible_widgets_;
502 }
503
504 void BrowserRenderProcessHost::AppendRendererCommandLine(
505 CommandLine* command_line) const {
506 // Pass the process type first, so it shows first in process listings.
507 command_line->AppendSwitchASCII(switches::kProcessType,
508 switches::kRendererProcess);
509
510 if (accessibility_enabled_)
511 command_line->AppendSwitch(switches::kEnableAccessibility);
512
513 // Now send any options from our own command line we want to propagate.
514 const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
515 PropagateBrowserCommandLineToRenderer(browser_command_line, command_line);
516
517 // Pass on the browser locale.
518 const std::string locale =
519 content::GetContentClient()->browser()->GetApplicationLocale();
520 command_line->AppendSwitchASCII(switches::kLang, locale);
521
522 // If we run base::FieldTrials, we want to pass to their state to the
523 // renderer so that it can act in accordance with each state, or record
524 // histograms relating to the base::FieldTrial states.
525 std::string field_trial_states;
526 base::FieldTrialList::StatesToString(&field_trial_states);
527 if (!field_trial_states.empty()) {
528 command_line->AppendSwitchASCII(switches::kForceFieldTestNameAndValue,
529 field_trial_states);
530 }
531
532 content::GetContentClient()->browser()->AppendExtraCommandLineSwitches(
533 command_line, id());
534
535 // Appending disable-gpu-feature switches due to software rendering list.
536 GpuDataManager* gpu_data_manager = GpuDataManager::GetInstance();
537 DCHECK(gpu_data_manager);
538 gpu_data_manager->AppendRendererCommandLine(command_line);
539 }
540
541 void BrowserRenderProcessHost::PropagateBrowserCommandLineToRenderer(
542 const CommandLine& browser_cmd,
543 CommandLine* renderer_cmd) const {
544 // Propagate the following switches to the renderer command line (along
545 // with any associated values) if present in the browser command line.
546 static const char* const kSwitchNames[] = {
547 // We propagate the Chrome Frame command line here as well in case the
548 // renderer is not run in the sandbox.
549 switches::kAuditAllHandles,
550 switches::kAuditHandles,
551 switches::kChromeFrame,
552 switches::kDisable3DAPIs,
553 switches::kDisableAcceleratedCompositing,
554 switches::kDisableApplicationCache,
555 switches::kDisableAudio,
556 switches::kDisableBreakpad,
557 switches::kDisableDataTransferItems,
558 switches::kDisableDatabases,
559 switches::kDisableDesktopNotifications,
560 switches::kDisableDeviceOrientation,
561 switches::kDisableFileSystem,
562 switches::kDisableGeolocation,
563 switches::kDisableGLMultisampling,
564 switches::kDisableGLSLTranslator,
565 switches::kDisableGpuDriverBugWorkarounds,
566 switches::kDisableGpuVsync,
567 switches::kDisableIndexedDatabase,
568 switches::kDisableJavaScriptI18NAPI,
569 switches::kDisableLocalStorage,
570 switches::kDisableLogging,
571 switches::kDisableSeccompSandbox,
572 switches::kDisableSessionStorage,
573 switches::kDisableSharedWorkers,
574 switches::kDisableSpeechInput,
575 switches::kDisableWebAudio,
576 switches::kDisableWebSockets,
577 switches::kEnableAccessibilityLogging,
578 switches::kEnableDCHECK,
579 switches::kEnableGamepad,
580 switches::kEnableGPUServiceLogging,
581 switches::kEnableGPUClientLogging,
582 switches::kEnableLogging,
583 switches::kEnableMediaSource,
584 switches::kEnableMediaStream,
585 switches::kEnableStrictSiteIsolation,
586 switches::kDisableFullScreen,
587 switches::kEnablePepperTesting,
588 #if defined(OS_MACOSX)
589 // Allow this to be set when invoking the browser and relayed along.
590 switches::kEnableSandboxLogging,
591 #endif
592 switches::kEnableSeccompSandbox,
593 switches::kEnableStatsTable,
594 switches::kEnableThreadedCompositing,
595 switches::kEnableVideoFullscreen,
596 switches::kEnableVideoLogging,
597 switches::kEnableVideoTrack,
598 switches::kFullMemoryCrashReport,
599 #if !defined (GOOGLE_CHROME_BUILD)
600 // These are unsupported and not fully tested modes, so don't enable them
601 // for official Google Chrome builds.
602 switches::kInProcessPlugins,
603 #endif // GOOGLE_CHROME_BUILD
604 switches::kInProcessWebGL,
605 switches::kJavaScriptFlags,
606 switches::kLoggingLevel,
607 switches::kHighLatencyAudio,
608 switches::kNoJsRandomness,
609 switches::kNoReferrers,
610 switches::kNoSandbox,
611 switches::kPlaybackMode,
612 switches::kPpapiOutOfProcess,
613 switches::kRecordMode,
614 switches::kRegisterPepperPlugins,
615 switches::kRemoteShellPort,
616 switches::kRendererAssertTest,
617 #if !defined(OFFICIAL_BUILD)
618 switches::kRendererCheckFalseTest,
619 #endif // !defined(OFFICIAL_BUILD)
620 switches::kRendererCrashTest,
621 switches::kRendererStartupDialog,
622 switches::kShowPaintRects,
623 switches::kSimpleDataSource,
624 switches::kTestSandbox,
625 switches::kTraceStartup,
626 // This flag needs to be propagated to the renderer process for
627 // --in-process-webgl.
628 switches::kUseGL,
629 switches::kUserAgent,
630 switches::kV,
631 switches::kVideoThreads,
632 switches::kVModule,
633 switches::kWebCoreLogChannels,
634 };
635 renderer_cmd->CopySwitchesFrom(browser_cmd, kSwitchNames,
636 arraysize(kSwitchNames));
637
638 // Disable databases in incognito mode.
639 if (browser_context()->IsOffTheRecord() &&
640 !browser_cmd.HasSwitch(switches::kDisableDatabases)) {
641 renderer_cmd->AppendSwitch(switches::kDisableDatabases);
642 }
643 }
644
645 base::ProcessHandle BrowserRenderProcessHost::GetHandle() {
646 // child_process_launcher_ is null either because we're in single process
647 // mode, we have done fast termination, or the process has crashed.
648 if (run_renderer_in_process() || !child_process_launcher_.get())
649 return base::Process::Current().handle();
650
651 if (child_process_launcher_->IsStarting())
652 return base::kNullProcessHandle;
653
654 return child_process_launcher_->GetHandle();
655 }
656
657 bool BrowserRenderProcessHost::FastShutdownIfPossible() {
658 if (run_renderer_in_process())
659 return false; // Single process mode can't do fast shutdown.
660
661 if (!content::GetContentClient()->browser()->IsFastShutdownPossible())
662 return false;
663
664 if (!child_process_launcher_.get() ||
665 child_process_launcher_->IsStarting() ||
666 !GetHandle())
667 return false; // Render process hasn't started or is probably crashed.
668
669 // Test if there's an unload listener.
670 // NOTE: It's possible that an onunload listener may be installed
671 // while we're shutting down, so there's a small race here. Given that
672 // the window is small, it's unlikely that the web page has much
673 // state that will be lost by not calling its unload handlers properly.
674 if (!sudden_termination_allowed())
675 return false;
676
677 // Store the handle before it gets changed.
678 base::ProcessHandle handle = GetHandle();
679 ProcessDied(handle, base::TERMINATION_STATUS_NORMAL_TERMINATION, 0, false);
680 fast_shutdown_started_ = true;
681 return true;
682 }
683
684 void BrowserRenderProcessHost::DumpHandles() {
685 #if defined(OS_WIN)
686 Send(new ChildProcessMsg_DumpHandles());
687 return;
688 #endif
689
690 NOTIMPLEMENTED();
691 }
692
693 // This is a platform specific function for mapping a transport DIB given its id
694 TransportDIB* BrowserRenderProcessHost::MapTransportDIB(
695 TransportDIB::Id dib_id) {
696 #if defined(OS_WIN)
697 // On Windows we need to duplicate the handle from the remote process
698 HANDLE section = chrome::GetSectionFromProcess(
699 dib_id.handle, GetHandle(), false /* read write */);
700 return TransportDIB::Map(section);
701 #elif defined(OS_MACOSX)
702 // On OSX, the browser allocates all DIBs and keeps a file descriptor around
703 // for each.
704 return widget_helper_->MapTransportDIB(dib_id);
705 #elif defined(OS_POSIX)
706 return TransportDIB::Map(dib_id.shmkey);
707 #endif // defined(OS_POSIX)
708 }
709
710 TransportDIB* BrowserRenderProcessHost::GetTransportDIB(
711 TransportDIB::Id dib_id) {
712 if (!TransportDIB::is_valid_id(dib_id))
713 return NULL;
714
715 const std::map<TransportDIB::Id, TransportDIB*>::iterator
716 i = cached_dibs_.find(dib_id);
717 if (i != cached_dibs_.end()) {
718 cached_dibs_cleaner_.Reset();
719 return i->second;
720 }
721
722 TransportDIB* dib = MapTransportDIB(dib_id);
723 if (!dib)
724 return NULL;
725
726 if (cached_dibs_.size() >= MAX_MAPPED_TRANSPORT_DIBS) {
727 // Clean a single entry from the cache
728 std::map<TransportDIB::Id, TransportDIB*>::iterator smallest_iterator;
729 size_t smallest_size = std::numeric_limits<size_t>::max();
730
731 for (std::map<TransportDIB::Id, TransportDIB*>::iterator
732 i = cached_dibs_.begin(); i != cached_dibs_.end(); ++i) {
733 if (i->second->size() <= smallest_size) {
734 smallest_iterator = i;
735 smallest_size = i->second->size();
736 }
737 }
738
739 delete smallest_iterator->second;
740 cached_dibs_.erase(smallest_iterator);
741 }
742
743 cached_dibs_[dib_id] = dib;
744 cached_dibs_cleaner_.Reset();
745 return dib;
746 }
747
748 void BrowserRenderProcessHost::ClearTransportDIBCache() {
749 STLDeleteContainerPairSecondPointers(
750 cached_dibs_.begin(), cached_dibs_.end());
751 cached_dibs_.clear();
752 }
753
754 void BrowserRenderProcessHost::SetCompositingSurface(
755 int render_widget_id,
756 gfx::PluginWindowHandle compositing_surface) {
757 widget_helper_->SetCompositingSurface(render_widget_id, compositing_surface);
758 }
759
760 bool BrowserRenderProcessHost::Send(IPC::Message* msg) {
761 if (!channel_.get()) {
762 if (!is_initialized_) {
763 queued_messages_.push(msg);
764 return true;
765 } else {
766 delete msg;
767 return false;
768 }
769 }
770
771 if (child_process_launcher_.get() && child_process_launcher_->IsStarting()) {
772 queued_messages_.push(msg);
773 return true;
774 }
775
776 return channel_->Send(msg);
777 }
778
779 bool BrowserRenderProcessHost::OnMessageReceived(const IPC::Message& msg) {
780 // If we're about to be deleted, or have initiated the fast shutdown sequence,
781 // we ignore incoming messages.
782
783 if (deleting_soon_ || fast_shutdown_started_)
784 return false;
785
786 mark_child_process_activity_time();
787 if (msg.routing_id() == MSG_ROUTING_CONTROL) {
788 // Dispatch control messages.
789 bool msg_is_ok = true;
790 IPC_BEGIN_MESSAGE_MAP_EX(BrowserRenderProcessHost, msg, msg_is_ok)
791 IPC_MESSAGE_HANDLER(ChildProcessHostMsg_ShutdownRequest,
792 OnShutdownRequest)
793 IPC_MESSAGE_HANDLER(ChildProcessHostMsg_DumpHandlesDone,
794 OnDumpHandlesDone)
795 IPC_MESSAGE_HANDLER(ViewHostMsg_SuddenTerminationChanged,
796 SuddenTerminationChanged)
797 IPC_MESSAGE_HANDLER(ViewHostMsg_UserMetricsRecordAction,
798 OnUserMetricsRecordAction)
799 IPC_MESSAGE_HANDLER(ViewHostMsg_RevealFolderInOS, OnRevealFolderInOS)
800 IPC_MESSAGE_HANDLER(ViewHostMsg_SavedPageAsMHTML, OnSavedPageAsMHTML)
801 IPC_MESSAGE_UNHANDLED_ERROR()
802 IPC_END_MESSAGE_MAP_EX()
803
804 if (!msg_is_ok) {
805 // The message had a handler, but its de-serialization failed.
806 // We consider this a capital crime. Kill the renderer if we have one.
807 LOG(ERROR) << "bad message " << msg.type() << " terminating renderer.";
808 UserMetrics::RecordAction(UserMetricsAction("BadMessageTerminate_BRPH"));
809 ReceivedBadMessage();
810 }
811 return true;
812 }
813
814 // Dispatch incoming messages to the appropriate RenderView/WidgetHost.
815 IPC::Channel::Listener* listener = GetListenerByID(msg.routing_id());
816 if (!listener) {
817 if (msg.is_sync()) {
818 // The listener has gone away, so we must respond or else the caller will
819 // hang waiting for a reply.
820 IPC::Message* reply = IPC::SyncMessage::GenerateReply(&msg);
821 reply->set_reply_error();
822 Send(reply);
823 }
824 return true;
825 }
826 return listener->OnMessageReceived(msg);
827 }
828
829 void BrowserRenderProcessHost::OnChannelConnected(int32 peer_pid) {
830 #if defined(IPC_MESSAGE_LOG_ENABLED)
831 Send(new ChildProcessMsg_SetIPCLoggingEnabled(
832 IPC::Logging::GetInstance()->Enabled()));
833 #endif
834
835 // Make sure the child checks with us before exiting, so that we do not try
836 // to schedule a new navigation in a swapped out and exiting renderer.
837 Send(new ChildProcessMsg_AskBeforeShutdown());
838 }
839
840 void BrowserRenderProcessHost::OnChannelError() {
841 if (!channel_.get())
842 return;
843
844 // Store the handle before it gets changed.
845 base::ProcessHandle handle = GetHandle();
846
847 // child_process_launcher_ can be NULL in single process mode or if fast
848 // termination happened.
849 int exit_code = 0;
850 base::TerminationStatus status =
851 child_process_launcher_.get() ?
852 child_process_launcher_->GetChildTerminationStatus(&exit_code) :
853 base::TERMINATION_STATUS_NORMAL_TERMINATION;
854
855 #if defined(OS_WIN)
856 if (!run_renderer_in_process()) {
857 if (status == base::TERMINATION_STATUS_STILL_RUNNING) {
858 HANDLE process = child_process_launcher_->GetHandle();
859 child_process_watcher_.StartWatching(
860 new base::WaitableEvent(process), this);
861 return;
862 }
863 }
864 #endif
865 ProcessDied(handle, status, exit_code, false);
866 }
867
868 // Called when the renderer process handle has been signaled.
869 void BrowserRenderProcessHost::OnWaitableEventSignaled(
870 base::WaitableEvent* waitable_event) {
871 #if defined (OS_WIN)
872 base::ProcessHandle handle = GetHandle();
873 int exit_code = 0;
874 base::TerminationStatus status =
875 base::GetTerminationStatus(waitable_event->Release(), &exit_code);
876 delete waitable_event;
877 ProcessDied(handle, status, exit_code, true);
878 #endif
879 }
880
881 void BrowserRenderProcessHost::ProcessDied(base::ProcessHandle handle,
882 base::TerminationStatus status,
883 int exit_code,
884 bool was_alive) {
885 // Our child process has died. If we didn't expect it, it's a crash.
886 // In any case, we need to let everyone know it's gone.
887 // The OnChannelError notification can fire multiple times due to nested sync
888 // calls to a renderer. If we don't have a valid channel here it means we
889 // already handled the error.
890
891 RendererClosedDetails details(handle, status, exit_code, was_alive);
892 content::NotificationService::current()->Notify(
893 content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
894 content::Source<RenderProcessHost>(this),
895 content::Details<RendererClosedDetails>(&details));
896
897 child_process_launcher_.reset();
898 channel_.reset();
899
900 IDMap<IPC::Channel::Listener>::iterator iter(&listeners_);
901 while (!iter.IsAtEnd()) {
902 iter.GetCurrentValue()->OnMessageReceived(
903 ViewHostMsg_RenderViewGone(iter.GetCurrentKey(),
904 static_cast<int>(status),
905 exit_code));
906 iter.Advance();
907 }
908
909 ClearTransportDIBCache();
910
911 // this object is not deleted at this point and may be reused later.
912 // TODO(darin): clean this up
913 }
914
915 void BrowserRenderProcessHost::OnShutdownRequest() {
916 // Don't shutdown if there are pending RenderViews being swapped back in.
917 if (pending_views_)
918 return;
919
920 // Notify any tabs that might have swapped out renderers from this process.
921 // They should not attempt to swap them back in.
922 content::NotificationService::current()->Notify(
923 content::NOTIFICATION_RENDERER_PROCESS_CLOSING,
924 content::Source<RenderProcessHost>(this),
925 content::NotificationService::NoDetails());
926
927 Send(new ChildProcessMsg_Shutdown());
928 }
929
930 void BrowserRenderProcessHost::OnDumpHandlesDone() {
931 Cleanup();
932 }
933
934 void BrowserRenderProcessHost::SuddenTerminationChanged(bool enabled) {
935 set_sudden_termination_allowed(enabled);
936 }
937
938 void BrowserRenderProcessHost::SetBackgrounded(bool backgrounded) {
939 // Note: we always set the backgrounded_ value. If the process is NULL
940 // (and hence hasn't been created yet), we will set the process priority
941 // later when we create the process.
942 backgrounded_ = backgrounded;
943 if (!child_process_launcher_.get() || child_process_launcher_->IsStarting())
944 return;
945
946 #if defined(OS_WIN)
947 // The cbstext.dll loads as a global GetMessage hook in the browser process
948 // and intercepts/unintercepts the kernel32 API SetPriorityClass in a
949 // background thread. If the UI thread invokes this API just when it is
950 // intercepted the stack is messed up on return from the interceptor
951 // which causes random crashes in the browser process. Our hack for now
952 // is to not invoke the SetPriorityClass API if the dll is loaded.
953 if (GetModuleHandle(L"cbstext.dll"))
954 return;
955 #endif // OS_WIN
956
957 child_process_launcher_->SetProcessBackgrounded(backgrounded);
958 }
959
960 void BrowserRenderProcessHost::OnProcessLaunched() {
961 // No point doing anything, since this object will be destructed soon. We
962 // especially don't want to send the RENDERER_PROCESS_CREATED notification,
963 // since some clients might expect a RENDERER_PROCESS_TERMINATED afterwards to
964 // properly cleanup.
965 if (deleting_soon_)
966 return;
967
968 if (child_process_launcher_.get()) {
969 if (!child_process_launcher_->GetHandle()) {
970 OnChannelError();
971 return;
972 }
973
974 child_process_launcher_->SetProcessBackgrounded(backgrounded_);
975 }
976
977 if (max_page_id_ != -1)
978 Send(new ViewMsg_SetNextPageID(max_page_id_ + 1));
979
980 // NOTE: This needs to be before sending queued messages because
981 // ExtensionService uses this notification to initialize the renderer process
982 // with state that must be there before any JavaScript executes.
983 //
984 // The queued messages contain such things as "navigate". If this notification
985 // was after, we can end up executing JavaScript before the initialization
986 // happens.
987 content::NotificationService::current()->Notify(
988 content::NOTIFICATION_RENDERER_PROCESS_CREATED,
989 content::Source<RenderProcessHost>(this),
990 content::NotificationService::NoDetails());
991
992 while (!queued_messages_.empty()) {
993 Send(queued_messages_.front());
994 queued_messages_.pop();
995 }
996 }
997
998 void BrowserRenderProcessHost::OnUserMetricsRecordAction(
999 const std::string& action) {
1000 UserMetrics::RecordComputedAction(action);
1001 }
1002
1003 void BrowserRenderProcessHost::OnRevealFolderInOS(const FilePath& path) {
1004 // Only honor the request if appropriate persmissions are granted.
1005 if (ChildProcessSecurityPolicy::GetInstance()->CanReadFile(id(), path))
1006 content::GetContentClient()->browser()->OpenItem(path);
1007 }
1008
1009 void BrowserRenderProcessHost::OnSavedPageAsMHTML(int job_id, int64 data_size) {
1010 content::GetContentClient()->browser()->GetMHTMLGenerationManager()->
1011 MHTMLGenerated(job_id, data_size);
1012 }
OLDNEW
« no previous file with comments | « content/browser/renderer_host/browser_render_process_host.h ('k') | content/browser/renderer_host/mock_render_process_host.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698