| OLD | NEW |
| (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 } | |
| OLD | NEW |