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

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::CancelResourceRequests(int render_widget_id) {
442 widget_helper_->CancelResourceRequests(render_widget_id);
443 }
444
445 void BrowserRenderProcessHost::CrossSiteSwapOutACK(
446 const ViewMsg_SwapOut_Params& params) {
447 widget_helper_->CrossSiteSwapOutACK(params);
448 }
449
450 bool BrowserRenderProcessHost::WaitForUpdateMsg(
451 int render_widget_id,
452 const base::TimeDelta& max_delay,
453 IPC::Message* msg) {
454 // The post task to this thread with the process id could be in queue, and we
455 // don't want to dispatch a message before then since it will need the handle.
456 if (child_process_launcher_.get() && child_process_launcher_->IsStarting())
457 return false;
458
459 return widget_helper_->WaitForUpdateMsg(render_widget_id, max_delay, msg);
460 }
461
462 void BrowserRenderProcessHost::ReceivedBadMessage() {
463 if (run_renderer_in_process()) {
464 // In single process mode it is better if we don't suicide but just
465 // crash.
466 CHECK(false);
467 }
468 NOTREACHED();
469 base::KillProcess(GetHandle(), content::RESULT_CODE_KILLED_BAD_MESSAGE,
470 false);
471 }
472
473 void BrowserRenderProcessHost::WidgetRestored() {
474 // Verify we were properly backgrounded.
475 DCHECK_EQ(backgrounded_, (visible_widgets_ == 0));
476 visible_widgets_++;
477 SetBackgrounded(false);
478 }
479
480 void BrowserRenderProcessHost::WidgetHidden() {
481 // On startup, the browser will call Hide
482 if (backgrounded_)
483 return;
484
485 DCHECK_EQ(backgrounded_, (visible_widgets_ == 0));
486 visible_widgets_--;
487 DCHECK_GE(visible_widgets_, 0);
488 if (visible_widgets_ == 0) {
489 DCHECK(!backgrounded_);
490 SetBackgrounded(true);
491 }
492 }
493
494 int BrowserRenderProcessHost::VisibleWidgetCount() const {
495 return visible_widgets_;
496 }
497
498 void BrowserRenderProcessHost::AppendRendererCommandLine(
499 CommandLine* command_line) const {
500 // Pass the process type first, so it shows first in process listings.
501 command_line->AppendSwitchASCII(switches::kProcessType,
502 switches::kRendererProcess);
503
504 if (accessibility_enabled_)
505 command_line->AppendSwitch(switches::kEnableAccessibility);
506
507 // Now send any options from our own command line we want to propagate.
508 const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
509 PropagateBrowserCommandLineToRenderer(browser_command_line, command_line);
510
511 // Pass on the browser locale.
512 const std::string locale =
513 content::GetContentClient()->browser()->GetApplicationLocale();
514 command_line->AppendSwitchASCII(switches::kLang, locale);
515
516 // If we run base::FieldTrials, we want to pass to their state to the
517 // renderer so that it can act in accordance with each state, or record
518 // histograms relating to the base::FieldTrial states.
519 std::string field_trial_states;
520 base::FieldTrialList::StatesToString(&field_trial_states);
521 if (!field_trial_states.empty()) {
522 command_line->AppendSwitchASCII(switches::kForceFieldTestNameAndValue,
523 field_trial_states);
524 }
525
526 content::GetContentClient()->browser()->AppendExtraCommandLineSwitches(
527 command_line, id());
528
529 // Appending disable-gpu-feature switches due to software rendering list.
530 GpuDataManager* gpu_data_manager = GpuDataManager::GetInstance();
531 DCHECK(gpu_data_manager);
532 gpu_data_manager->AppendRendererCommandLine(command_line);
533 }
534
535 void BrowserRenderProcessHost::PropagateBrowserCommandLineToRenderer(
536 const CommandLine& browser_cmd,
537 CommandLine* renderer_cmd) const {
538 // Propagate the following switches to the renderer command line (along
539 // with any associated values) if present in the browser command line.
540 static const char* const kSwitchNames[] = {
541 // We propagate the Chrome Frame command line here as well in case the
542 // renderer is not run in the sandbox.
543 switches::kAuditAllHandles,
544 switches::kAuditHandles,
545 switches::kChromeFrame,
546 switches::kDisable3DAPIs,
547 switches::kDisableAcceleratedCompositing,
548 switches::kDisableApplicationCache,
549 switches::kDisableAudio,
550 switches::kDisableBreakpad,
551 switches::kDisableDataTransferItems,
552 switches::kDisableDatabases,
553 switches::kDisableDesktopNotifications,
554 switches::kDisableDeviceOrientation,
555 switches::kDisableFileSystem,
556 switches::kDisableGeolocation,
557 switches::kDisableGLMultisampling,
558 switches::kDisableGLSLTranslator,
559 switches::kDisableGpuDriverBugWorkarounds,
560 switches::kDisableGpuVsync,
561 switches::kDisableIndexedDatabase,
562 switches::kDisableJavaScriptI18NAPI,
563 switches::kDisableLocalStorage,
564 switches::kDisableLogging,
565 switches::kDisableSeccompSandbox,
566 switches::kDisableSessionStorage,
567 switches::kDisableSharedWorkers,
568 switches::kDisableSpeechInput,
569 switches::kDisableWebAudio,
570 switches::kDisableWebSockets,
571 switches::kEnableAccessibilityLogging,
572 switches::kEnableDCHECK,
573 switches::kEnableGamepad,
574 switches::kEnableGPUServiceLogging,
575 switches::kEnableGPUClientLogging,
576 switches::kEnableLogging,
577 switches::kEnableMediaSource,
578 switches::kEnableMediaStream,
579 switches::kEnableStrictSiteIsolation,
580 switches::kDisableFullScreen,
581 switches::kEnablePepperTesting,
582 #if defined(OS_MACOSX)
583 // Allow this to be set when invoking the browser and relayed along.
584 switches::kEnableSandboxLogging,
585 #endif
586 switches::kEnableSeccompSandbox,
587 switches::kEnableStatsTable,
588 switches::kEnableThreadedCompositing,
589 switches::kEnableVideoFullscreen,
590 switches::kEnableVideoLogging,
591 switches::kEnableVideoTrack,
592 switches::kFullMemoryCrashReport,
593 #if !defined (GOOGLE_CHROME_BUILD)
594 // These are unsupported and not fully tested modes, so don't enable them
595 // for official Google Chrome builds.
596 switches::kInProcessPlugins,
597 #endif // GOOGLE_CHROME_BUILD
598 switches::kInProcessWebGL,
599 switches::kJavaScriptFlags,
600 switches::kLoggingLevel,
601 switches::kHighLatencyAudio,
602 switches::kNoJsRandomness,
603 switches::kNoReferrers,
604 switches::kNoSandbox,
605 switches::kPlaybackMode,
606 switches::kPpapiOutOfProcess,
607 switches::kRecordMode,
608 switches::kRegisterPepperPlugins,
609 switches::kRemoteShellPort,
610 switches::kRendererAssertTest,
611 #if !defined(OFFICIAL_BUILD)
612 switches::kRendererCheckFalseTest,
613 #endif // !defined(OFFICIAL_BUILD)
614 switches::kRendererCrashTest,
615 switches::kRendererStartupDialog,
616 switches::kShowPaintRects,
617 switches::kSimpleDataSource,
618 switches::kTestSandbox,
619 switches::kTraceStartup,
620 // This flag needs to be propagated to the renderer process for
621 // --in-process-webgl.
622 switches::kUseGL,
623 switches::kUserAgent,
624 switches::kV,
625 switches::kVideoThreads,
626 switches::kVModule,
627 switches::kWebCoreLogChannels,
628 };
629 renderer_cmd->CopySwitchesFrom(browser_cmd, kSwitchNames,
630 arraysize(kSwitchNames));
631
632 // Disable databases in incognito mode.
633 if (browser_context()->IsOffTheRecord() &&
634 !browser_cmd.HasSwitch(switches::kDisableDatabases)) {
635 renderer_cmd->AppendSwitch(switches::kDisableDatabases);
636 }
637 }
638
639 base::ProcessHandle BrowserRenderProcessHost::GetHandle() {
640 // child_process_launcher_ is null either because we're in single process
641 // mode, we have done fast termination, or the process has crashed.
642 if (run_renderer_in_process() || !child_process_launcher_.get())
643 return base::Process::Current().handle();
644
645 if (child_process_launcher_->IsStarting())
646 return base::kNullProcessHandle;
647
648 return child_process_launcher_->GetHandle();
649 }
650
651 bool BrowserRenderProcessHost::FastShutdownIfPossible() {
652 if (run_renderer_in_process())
653 return false; // Single process mode can't do fast shutdown.
654
655 if (!content::GetContentClient()->browser()->IsFastShutdownPossible())
656 return false;
657
658 if (!child_process_launcher_.get() ||
659 child_process_launcher_->IsStarting() ||
660 !GetHandle())
661 return false; // Render process hasn't started or is probably crashed.
662
663 // Test if there's an unload listener.
664 // NOTE: It's possible that an onunload listener may be installed
665 // while we're shutting down, so there's a small race here. Given that
666 // the window is small, it's unlikely that the web page has much
667 // state that will be lost by not calling its unload handlers properly.
668 if (!sudden_termination_allowed())
669 return false;
670
671 // Store the handle before it gets changed.
672 base::ProcessHandle handle = GetHandle();
673 ProcessDied(handle, base::TERMINATION_STATUS_NORMAL_TERMINATION, 0, false);
674 fast_shutdown_started_ = true;
675 return true;
676 }
677
678 void BrowserRenderProcessHost::DumpHandles() {
679 #if defined(OS_WIN)
680 Send(new ChildProcessMsg_DumpHandles());
681 return;
682 #endif
683
684 NOTIMPLEMENTED();
685 }
686
687 // This is a platform specific function for mapping a transport DIB given its id
688 TransportDIB* BrowserRenderProcessHost::MapTransportDIB(
689 TransportDIB::Id dib_id) {
690 #if defined(OS_WIN)
691 // On Windows we need to duplicate the handle from the remote process
692 HANDLE section = chrome::GetSectionFromProcess(
693 dib_id.handle, GetHandle(), false /* read write */);
694 return TransportDIB::Map(section);
695 #elif defined(OS_MACOSX)
696 // On OSX, the browser allocates all DIBs and keeps a file descriptor around
697 // for each.
698 return widget_helper_->MapTransportDIB(dib_id);
699 #elif defined(OS_POSIX)
700 return TransportDIB::Map(dib_id.shmkey);
701 #endif // defined(OS_POSIX)
702 }
703
704 TransportDIB* BrowserRenderProcessHost::GetTransportDIB(
705 TransportDIB::Id dib_id) {
706 if (!TransportDIB::is_valid_id(dib_id))
707 return NULL;
708
709 const std::map<TransportDIB::Id, TransportDIB*>::iterator
710 i = cached_dibs_.find(dib_id);
711 if (i != cached_dibs_.end()) {
712 cached_dibs_cleaner_.Reset();
713 return i->second;
714 }
715
716 TransportDIB* dib = MapTransportDIB(dib_id);
717 if (!dib)
718 return NULL;
719
720 if (cached_dibs_.size() >= MAX_MAPPED_TRANSPORT_DIBS) {
721 // Clean a single entry from the cache
722 std::map<TransportDIB::Id, TransportDIB*>::iterator smallest_iterator;
723 size_t smallest_size = std::numeric_limits<size_t>::max();
724
725 for (std::map<TransportDIB::Id, TransportDIB*>::iterator
726 i = cached_dibs_.begin(); i != cached_dibs_.end(); ++i) {
727 if (i->second->size() <= smallest_size) {
728 smallest_iterator = i;
729 smallest_size = i->second->size();
730 }
731 }
732
733 delete smallest_iterator->second;
734 cached_dibs_.erase(smallest_iterator);
735 }
736
737 cached_dibs_[dib_id] = dib;
738 cached_dibs_cleaner_.Reset();
739 return dib;
740 }
741
742 void BrowserRenderProcessHost::ClearTransportDIBCache() {
743 STLDeleteContainerPairSecondPointers(
744 cached_dibs_.begin(), cached_dibs_.end());
745 cached_dibs_.clear();
746 }
747
748 void BrowserRenderProcessHost::SetCompositingSurface(
749 int render_widget_id,
750 gfx::PluginWindowHandle compositing_surface) {
751 widget_helper_->SetCompositingSurface(render_widget_id, compositing_surface);
752 }
753
754 bool BrowserRenderProcessHost::Send(IPC::Message* msg) {
755 if (!channel_.get()) {
756 if (!is_initialized_) {
757 queued_messages_.push(msg);
758 return true;
759 } else {
760 delete msg;
761 return false;
762 }
763 }
764
765 if (child_process_launcher_.get() && child_process_launcher_->IsStarting()) {
766 queued_messages_.push(msg);
767 return true;
768 }
769
770 return channel_->Send(msg);
771 }
772
773 bool BrowserRenderProcessHost::OnMessageReceived(const IPC::Message& msg) {
774 // If we're about to be deleted, or have initiated the fast shutdown sequence,
775 // we ignore incoming messages.
776
777 if (deleting_soon_ || fast_shutdown_started_)
778 return false;
779
780 mark_child_process_activity_time();
781 if (msg.routing_id() == MSG_ROUTING_CONTROL) {
782 // Dispatch control messages.
783 bool msg_is_ok = true;
784 IPC_BEGIN_MESSAGE_MAP_EX(BrowserRenderProcessHost, msg, msg_is_ok)
785 IPC_MESSAGE_HANDLER(ChildProcessHostMsg_ShutdownRequest,
786 OnShutdownRequest)
787 IPC_MESSAGE_HANDLER(ChildProcessHostMsg_DumpHandlesDone,
788 OnDumpHandlesDone)
789 IPC_MESSAGE_HANDLER(ViewHostMsg_SuddenTerminationChanged,
790 SuddenTerminationChanged)
791 IPC_MESSAGE_HANDLER(ViewHostMsg_UserMetricsRecordAction,
792 OnUserMetricsRecordAction)
793 IPC_MESSAGE_HANDLER(ViewHostMsg_RevealFolderInOS, OnRevealFolderInOS)
794 IPC_MESSAGE_HANDLER(ViewHostMsg_SavedPageAsMHTML, OnSavedPageAsMHTML)
795 IPC_MESSAGE_UNHANDLED_ERROR()
796 IPC_END_MESSAGE_MAP_EX()
797
798 if (!msg_is_ok) {
799 // The message had a handler, but its de-serialization failed.
800 // We consider this a capital crime. Kill the renderer if we have one.
801 LOG(ERROR) << "bad message " << msg.type() << " terminating renderer.";
802 UserMetrics::RecordAction(UserMetricsAction("BadMessageTerminate_BRPH"));
803 ReceivedBadMessage();
804 }
805 return true;
806 }
807
808 // Dispatch incoming messages to the appropriate RenderView/WidgetHost.
809 IPC::Channel::Listener* listener = GetListenerByID(msg.routing_id());
810 if (!listener) {
811 if (msg.is_sync()) {
812 // The listener has gone away, so we must respond or else the caller will
813 // hang waiting for a reply.
814 IPC::Message* reply = IPC::SyncMessage::GenerateReply(&msg);
815 reply->set_reply_error();
816 Send(reply);
817 }
818 return true;
819 }
820 return listener->OnMessageReceived(msg);
821 }
822
823 void BrowserRenderProcessHost::OnChannelConnected(int32 peer_pid) {
824 #if defined(IPC_MESSAGE_LOG_ENABLED)
825 Send(new ChildProcessMsg_SetIPCLoggingEnabled(
826 IPC::Logging::GetInstance()->Enabled()));
827 #endif
828
829 // Make sure the child checks with us before exiting, so that we do not try
830 // to schedule a new navigation in a swapped out and exiting renderer.
831 Send(new ChildProcessMsg_AskBeforeShutdown());
832 }
833
834 void BrowserRenderProcessHost::OnChannelError() {
835 if (!channel_.get())
836 return;
837
838 // Store the handle before it gets changed.
839 base::ProcessHandle handle = GetHandle();
840
841 // child_process_launcher_ can be NULL in single process mode or if fast
842 // termination happened.
843 int exit_code = 0;
844 base::TerminationStatus status =
845 child_process_launcher_.get() ?
846 child_process_launcher_->GetChildTerminationStatus(&exit_code) :
847 base::TERMINATION_STATUS_NORMAL_TERMINATION;
848
849 #if defined(OS_WIN)
850 if (!run_renderer_in_process()) {
851 if (status == base::TERMINATION_STATUS_STILL_RUNNING) {
852 HANDLE process = child_process_launcher_->GetHandle();
853 child_process_watcher_.StartWatching(
854 new base::WaitableEvent(process), this);
855 return;
856 }
857 }
858 #endif
859 ProcessDied(handle, status, exit_code, false);
860 }
861
862 // Called when the renderer process handle has been signaled.
863 void BrowserRenderProcessHost::OnWaitableEventSignaled(
864 base::WaitableEvent* waitable_event) {
865 #if defined (OS_WIN)
866 base::ProcessHandle handle = GetHandle();
867 int exit_code = 0;
868 base::TerminationStatus status =
869 base::GetTerminationStatus(waitable_event->Release(), &exit_code);
870 delete waitable_event;
871 ProcessDied(handle, status, exit_code, true);
872 #endif
873 }
874
875 void BrowserRenderProcessHost::ProcessDied(base::ProcessHandle handle,
876 base::TerminationStatus status,
877 int exit_code,
878 bool was_alive) {
879 // Our child process has died. If we didn't expect it, it's a crash.
880 // In any case, we need to let everyone know it's gone.
881 // The OnChannelError notification can fire multiple times due to nested sync
882 // calls to a renderer. If we don't have a valid channel here it means we
883 // already handled the error.
884
885 RendererClosedDetails details(handle, status, exit_code, was_alive);
886 content::NotificationService::current()->Notify(
887 content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
888 content::Source<RenderProcessHost>(this),
889 content::Details<RendererClosedDetails>(&details));
890
891 child_process_launcher_.reset();
892 channel_.reset();
893
894 IDMap<IPC::Channel::Listener>::iterator iter(&listeners_);
895 while (!iter.IsAtEnd()) {
896 iter.GetCurrentValue()->OnMessageReceived(
897 ViewHostMsg_RenderViewGone(iter.GetCurrentKey(),
898 static_cast<int>(status),
899 exit_code));
900 iter.Advance();
901 }
902
903 ClearTransportDIBCache();
904
905 // this object is not deleted at this point and may be reused later.
906 // TODO(darin): clean this up
907 }
908
909 void BrowserRenderProcessHost::OnShutdownRequest() {
910 // Don't shutdown if there are pending RenderViews being swapped back in.
911 if (pending_views_)
912 return;
913
914 // Notify any tabs that might have swapped out renderers from this process.
915 // They should not attempt to swap them back in.
916 content::NotificationService::current()->Notify(
917 content::NOTIFICATION_RENDERER_PROCESS_CLOSING,
918 content::Source<RenderProcessHost>(this),
919 content::NotificationService::NoDetails());
920
921 Send(new ChildProcessMsg_Shutdown());
922 }
923
924 void BrowserRenderProcessHost::OnDumpHandlesDone() {
925 Cleanup();
926 }
927
928 void BrowserRenderProcessHost::SuddenTerminationChanged(bool enabled) {
929 set_sudden_termination_allowed(enabled);
930 }
931
932 void BrowserRenderProcessHost::SetBackgrounded(bool backgrounded) {
933 // Note: we always set the backgrounded_ value. If the process is NULL
934 // (and hence hasn't been created yet), we will set the process priority
935 // later when we create the process.
936 backgrounded_ = backgrounded;
937 if (!child_process_launcher_.get() || child_process_launcher_->IsStarting())
938 return;
939
940 #if defined(OS_WIN)
941 // The cbstext.dll loads as a global GetMessage hook in the browser process
942 // and intercepts/unintercepts the kernel32 API SetPriorityClass in a
943 // background thread. If the UI thread invokes this API just when it is
944 // intercepted the stack is messed up on return from the interceptor
945 // which causes random crashes in the browser process. Our hack for now
946 // is to not invoke the SetPriorityClass API if the dll is loaded.
947 if (GetModuleHandle(L"cbstext.dll"))
948 return;
949 #endif // OS_WIN
950
951 child_process_launcher_->SetProcessBackgrounded(backgrounded);
952 }
953
954 void BrowserRenderProcessHost::OnProcessLaunched() {
955 // No point doing anything, since this object will be destructed soon. We
956 // especially don't want to send the RENDERER_PROCESS_CREATED notification,
957 // since some clients might expect a RENDERER_PROCESS_TERMINATED afterwards to
958 // properly cleanup.
959 if (deleting_soon_)
960 return;
961
962 if (child_process_launcher_.get()) {
963 if (!child_process_launcher_->GetHandle()) {
964 OnChannelError();
965 return;
966 }
967
968 child_process_launcher_->SetProcessBackgrounded(backgrounded_);
969 }
970
971 if (max_page_id_ != -1)
972 Send(new ViewMsg_SetNextPageID(max_page_id_ + 1));
973
974 // NOTE: This needs to be before sending queued messages because
975 // ExtensionService uses this notification to initialize the renderer process
976 // with state that must be there before any JavaScript executes.
977 //
978 // The queued messages contain such things as "navigate". If this notification
979 // was after, we can end up executing JavaScript before the initialization
980 // happens.
981 content::NotificationService::current()->Notify(
982 content::NOTIFICATION_RENDERER_PROCESS_CREATED,
983 content::Source<RenderProcessHost>(this),
984 content::NotificationService::NoDetails());
985
986 while (!queued_messages_.empty()) {
987 Send(queued_messages_.front());
988 queued_messages_.pop();
989 }
990 }
991
992 void BrowserRenderProcessHost::OnUserMetricsRecordAction(
993 const std::string& action) {
994 UserMetrics::RecordComputedAction(action);
995 }
996
997 void BrowserRenderProcessHost::OnRevealFolderInOS(const FilePath& path) {
998 // Only honor the request if appropriate persmissions are granted.
999 if (ChildProcessSecurityPolicy::GetInstance()->CanReadFile(id(), path))
1000 content::GetContentClient()->browser()->OpenItem(path);
1001 }
1002
1003 void BrowserRenderProcessHost::OnSavedPageAsMHTML(int job_id, int64 data_size) {
1004 content::GetContentClient()->browser()->GetMHTMLGenerationManager()->
1005 MHTMLGenerated(job_id, data_size);
1006 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698