| Index: content/browser/renderer_host/browser_render_process_host.cc
|
| ===================================================================
|
| --- content/browser/renderer_host/browser_render_process_host.cc (revision 110571)
|
| +++ content/browser/renderer_host/browser_render_process_host.cc (working copy)
|
| @@ -1,1012 +0,0 @@
|
| -// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -// Represents the browser side of the browser <--> renderer communication
|
| -// channel. There will be one RenderProcessHost per renderer process.
|
| -
|
| -#include "content/browser/renderer_host/browser_render_process_host.h"
|
| -
|
| -#include <algorithm>
|
| -#include <limits>
|
| -#include <vector>
|
| -
|
| -#if defined(OS_POSIX)
|
| -#include <utility> // for pair<>
|
| -#endif
|
| -
|
| -#include "base/base_switches.h"
|
| -#include "base/bind.h"
|
| -#include "base/bind_helpers.h"
|
| -#include "base/callback.h"
|
| -#include "base/command_line.h"
|
| -#include "base/logging.h"
|
| -#include "base/metrics/field_trial.h"
|
| -#include "base/metrics/histogram.h"
|
| -#include "base/path_service.h"
|
| -#include "base/platform_file.h"
|
| -#include "base/stl_util.h"
|
| -#include "base/string_util.h"
|
| -#include "base/threading/thread.h"
|
| -#include "base/threading/thread_restrictions.h"
|
| -#include "content/browser/appcache/appcache_dispatcher_host.h"
|
| -#include "content/browser/browser_child_process_host.h"
|
| -#include "content/browser/browser_context.h"
|
| -#include "content/browser/child_process_security_policy.h"
|
| -#include "content/browser/device_orientation/message_filter.h"
|
| -#include "content/browser/download/mhtml_generation_manager.h"
|
| -#include "content/browser/file_system/file_system_dispatcher_host.h"
|
| -#include "content/browser/geolocation/geolocation_dispatcher_host.h"
|
| -#include "content/browser/gpu/gpu_data_manager.h"
|
| -#include "content/browser/gpu/gpu_process_host.h"
|
| -#include "content/browser/in_process_webkit/dom_storage_message_filter.h"
|
| -#include "content/browser/in_process_webkit/indexed_db_dispatcher_host.h"
|
| -#include "content/browser/mime_registry_message_filter.h"
|
| -#include "content/browser/plugin_service.h"
|
| -#include "content/browser/renderer_host/blob_message_filter.h"
|
| -#include "content/browser/renderer_host/clipboard_message_filter.h"
|
| -#include "content/browser/renderer_host/database_message_filter.h"
|
| -#include "content/browser/renderer_host/file_utilities_message_filter.h"
|
| -#include "content/browser/renderer_host/gpu_message_filter.h"
|
| -#include "content/browser/renderer_host/media/audio_input_renderer_host.h"
|
| -#include "content/browser/renderer_host/media/audio_renderer_host.h"
|
| -#include "content/browser/renderer_host/media/media_stream_dispatcher_host.h"
|
| -#include "content/browser/renderer_host/media/video_capture_host.h"
|
| -#include "content/browser/renderer_host/p2p/socket_dispatcher_host.h"
|
| -#include "content/browser/renderer_host/pepper_file_message_filter.h"
|
| -#include "content/browser/renderer_host/pepper_message_filter.h"
|
| -#include "content/browser/renderer_host/quota_dispatcher_host.h"
|
| -#include "content/browser/renderer_host/render_message_filter.h"
|
| -#include "content/browser/renderer_host/render_view_host.h"
|
| -#include "content/browser/renderer_host/render_view_host_delegate.h"
|
| -#include "content/browser/renderer_host/render_widget_helper.h"
|
| -#include "content/browser/renderer_host/render_widget_host.h"
|
| -#include "content/browser/renderer_host/resource_message_filter.h"
|
| -#include "content/browser/renderer_host/socket_stream_dispatcher_host.h"
|
| -#include "content/browser/renderer_host/text_input_client_message_filter.h"
|
| -#include "content/browser/resolve_proxy_msg_helper.h"
|
| -#include "content/browser/speech/speech_input_dispatcher_host.h"
|
| -#include "content/browser/trace_message_filter.h"
|
| -#include "content/browser/user_metrics.h"
|
| -#include "content/browser/worker_host/worker_message_filter.h"
|
| -#include "content/common/child_process_info.h"
|
| -#include "content/common/child_process_messages.h"
|
| -#include "content/common/gpu/gpu_messages.h"
|
| -#include "content/public/browser/notification_service.h"
|
| -#include "content/common/process_watcher.h"
|
| -#include "content/common/resource_messages.h"
|
| -#include "content/common/view_messages.h"
|
| -#include "content/public/browser/content_browser_client.h"
|
| -#include "content/public/common/content_switches.h"
|
| -#include "content/public/common/result_codes.h"
|
| -#include "content/renderer/render_process_impl.h"
|
| -#include "content/renderer/render_thread_impl.h"
|
| -#include "ipc/ipc_logging.h"
|
| -#include "ipc/ipc_platform_file.h"
|
| -#include "ipc/ipc_switches.h"
|
| -#include "media/base/media_switches.h"
|
| -#include "net/url_request/url_request_context_getter.h"
|
| -#include "ui/base/ui_base_switches.h"
|
| -#include "ui/gfx/gl/gl_switches.h"
|
| -#include "webkit/fileapi/file_system_path_manager.h"
|
| -#include "webkit/fileapi/sandbox_mount_point_provider.h"
|
| -#include "webkit/glue/resource_type.h"
|
| -#include "webkit/plugins/plugin_switches.h"
|
| -
|
| -#if defined(OS_WIN)
|
| -#include <objbase.h>
|
| -#include "base/synchronization/waitable_event.h"
|
| -#include "content/common/section_util_win.h"
|
| -#endif
|
| -
|
| -#include "third_party/skia/include/core/SkBitmap.h"
|
| -
|
| -using content::BrowserThread;
|
| -
|
| -// This class creates the IO thread for the renderer when running in
|
| -// single-process mode. It's not used in multi-process mode.
|
| -class RendererMainThread : public base::Thread {
|
| - public:
|
| - explicit RendererMainThread(const std::string& channel_id)
|
| - : base::Thread("Chrome_InProcRendererThread"),
|
| - channel_id_(channel_id),
|
| - render_process_(NULL) {
|
| - }
|
| -
|
| - ~RendererMainThread() {
|
| - Stop();
|
| - }
|
| -
|
| - protected:
|
| - virtual void Init() {
|
| -#if defined(OS_WIN)
|
| - CoInitialize(NULL);
|
| -#endif
|
| -
|
| - render_process_ = new RenderProcessImpl();
|
| - render_process_->set_main_thread(new RenderThreadImpl(channel_id_));
|
| - }
|
| -
|
| - virtual void CleanUp() {
|
| - delete render_process_;
|
| -
|
| -#if defined(OS_WIN)
|
| - CoUninitialize();
|
| -#endif
|
| - // It's a little lame to manually set this flag. But the single process
|
| - // RendererThread will receive the WM_QUIT. We don't need to assert on
|
| - // this thread, so just force the flag manually.
|
| - // If we want to avoid this, we could create the InProcRendererThread
|
| - // directly with _beginthreadex() rather than using the Thread class.
|
| - // We used to set this flag in the Init function above. However there
|
| - // other threads like WebThread which are created by this thread
|
| - // which resets this flag. Please see Thread::StartWithOptions. Setting
|
| - // this flag to true in Cleanup works around these problems.
|
| - base::Thread::SetThreadWasQuitProperly(true);
|
| - }
|
| -
|
| - private:
|
| - std::string channel_id_;
|
| - // Deleted in CleanUp() on the renderer thread, so don't use a smart pointer.
|
| - RenderProcess* render_process_;
|
| -};
|
| -
|
| -namespace {
|
| -
|
| -// Helper class that we pass to ResourceMessageFilter so that it can find the
|
| -// right net::URLRequestContext for a request.
|
| -class RendererURLRequestContextSelector
|
| - : public ResourceMessageFilter::URLRequestContextSelector {
|
| - public:
|
| - RendererURLRequestContextSelector(content::BrowserContext* browser_context,
|
| - int render_child_id)
|
| - : request_context_(browser_context->GetRequestContextForRenderProcess(
|
| - render_child_id)),
|
| - media_request_context_(browser_context->GetRequestContextForMedia()) {
|
| - }
|
| -
|
| - virtual net::URLRequestContext* GetRequestContext(
|
| - ResourceType::Type resource_type) {
|
| - net::URLRequestContextGetter* request_context = request_context_;
|
| - // If the request has resource type of ResourceType::MEDIA, we use a request
|
| - // context specific to media for handling it because these resources have
|
| - // specific needs for caching.
|
| - if (resource_type == ResourceType::MEDIA)
|
| - request_context = media_request_context_;
|
| - return request_context->GetURLRequestContext();
|
| - }
|
| -
|
| - private:
|
| - virtual ~RendererURLRequestContextSelector() {}
|
| -
|
| - scoped_refptr<net::URLRequestContextGetter> request_context_;
|
| - scoped_refptr<net::URLRequestContextGetter> media_request_context_;
|
| -};
|
| -
|
| -} // namespace
|
| -
|
| -BrowserRenderProcessHost::BrowserRenderProcessHost(
|
| - content::BrowserContext* browser_context)
|
| - : RenderProcessHost(browser_context),
|
| - visible_widgets_(0),
|
| - backgrounded_(true),
|
| - ALLOW_THIS_IN_INITIALIZER_LIST(cached_dibs_cleaner_(
|
| - FROM_HERE, base::TimeDelta::FromSeconds(5),
|
| - this, &BrowserRenderProcessHost::ClearTransportDIBCache)),
|
| - accessibility_enabled_(false),
|
| - is_initialized_(false) {
|
| - widget_helper_ = new RenderWidgetHelper();
|
| -
|
| - ChildProcessSecurityPolicy::GetInstance()->Add(id());
|
| -
|
| - // Grant most file permissions to this renderer.
|
| - // PLATFORM_FILE_TEMPORARY, PLATFORM_FILE_HIDDEN and
|
| - // PLATFORM_FILE_DELETE_ON_CLOSE are not granted, because no existing API
|
| - // requests them.
|
| - // This is for the filesystem sandbox.
|
| - ChildProcessSecurityPolicy::GetInstance()->GrantPermissionsForFile(
|
| - id(), browser_context->GetPath().Append(
|
| - fileapi::SandboxMountPointProvider::kNewFileSystemDirectory),
|
| - base::PLATFORM_FILE_OPEN |
|
| - base::PLATFORM_FILE_CREATE |
|
| - base::PLATFORM_FILE_OPEN_ALWAYS |
|
| - base::PLATFORM_FILE_CREATE_ALWAYS |
|
| - base::PLATFORM_FILE_OPEN_TRUNCATED |
|
| - base::PLATFORM_FILE_READ |
|
| - base::PLATFORM_FILE_WRITE |
|
| - base::PLATFORM_FILE_EXCLUSIVE_READ |
|
| - base::PLATFORM_FILE_EXCLUSIVE_WRITE |
|
| - base::PLATFORM_FILE_ASYNC |
|
| - base::PLATFORM_FILE_WRITE_ATTRIBUTES |
|
| - base::PLATFORM_FILE_ENUMERATE);
|
| - // This is so that we can read and move stuff out of the old filesystem
|
| - // sandbox.
|
| - ChildProcessSecurityPolicy::GetInstance()->GrantPermissionsForFile(
|
| - id(), browser_context->GetPath().Append(
|
| - fileapi::SandboxMountPointProvider::kOldFileSystemDirectory),
|
| - base::PLATFORM_FILE_READ | base::PLATFORM_FILE_WRITE |
|
| - base::PLATFORM_FILE_WRITE_ATTRIBUTES | base::PLATFORM_FILE_ENUMERATE);
|
| - // This is so that we can rename the old sandbox out of the way so that we
|
| - // know we've taken care of it.
|
| - ChildProcessSecurityPolicy::GetInstance()->GrantPermissionsForFile(
|
| - id(), browser_context->GetPath().Append(
|
| - fileapi::SandboxMountPointProvider::kRenamedOldFileSystemDirectory),
|
| - base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_CREATE_ALWAYS |
|
| - base::PLATFORM_FILE_WRITE);
|
| -
|
| - // Note: When we create the BrowserRenderProcessHost, it's technically
|
| - // backgrounded, because it has no visible listeners. But the process
|
| - // doesn't actually exist yet, so we'll Background it later, after
|
| - // creation.
|
| -}
|
| -
|
| -BrowserRenderProcessHost::~BrowserRenderProcessHost() {
|
| - ChildProcessSecurityPolicy::GetInstance()->Remove(id());
|
| -
|
| - // We may have some unsent messages at this point, but that's OK.
|
| - channel_.reset();
|
| - while (!queued_messages_.empty()) {
|
| - delete queued_messages_.front();
|
| - queued_messages_.pop();
|
| - }
|
| -
|
| - ClearTransportDIBCache();
|
| -}
|
| -
|
| -void BrowserRenderProcessHost::EnableSendQueue() {
|
| - is_initialized_ = false;
|
| -}
|
| -
|
| -bool BrowserRenderProcessHost::Init(bool is_accessibility_enabled) {
|
| - // calling Init() more than once does nothing, this makes it more convenient
|
| - // for the view host which may not be sure in some cases
|
| - if (channel_.get())
|
| - return true;
|
| -
|
| - accessibility_enabled_ = is_accessibility_enabled;
|
| -
|
| - CommandLine::StringType renderer_prefix;
|
| -#if defined(OS_POSIX)
|
| - // A command prefix is something prepended to the command line of the spawned
|
| - // process. It is supported only on POSIX systems.
|
| - const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
|
| - renderer_prefix =
|
| - browser_command_line.GetSwitchValueNative(switches::kRendererCmdPrefix);
|
| -#endif // defined(OS_POSIX)
|
| -
|
| -#if defined(OS_LINUX)
|
| - int flags = renderer_prefix.empty() ? ChildProcessHost::CHILD_ALLOW_SELF :
|
| - ChildProcessHost::CHILD_NORMAL;
|
| -#else
|
| - int flags = ChildProcessHost::CHILD_NORMAL;
|
| -#endif
|
| -
|
| - // Find the renderer before creating the channel so if this fails early we
|
| - // return without creating the channel.
|
| - FilePath renderer_path = ChildProcessHost::GetChildPath(flags);
|
| - if (renderer_path.empty())
|
| - return false;
|
| -
|
| - // Setup the IPC channel.
|
| - const std::string channel_id =
|
| - ChildProcessInfo::GenerateRandomChannelID(this);
|
| - channel_.reset(new IPC::ChannelProxy(
|
| - channel_id, IPC::Channel::MODE_SERVER, this,
|
| - BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO)));
|
| -
|
| - // Call the embedder first so that their IPC filters have priority.
|
| - content::GetContentClient()->browser()->BrowserRenderProcessHostCreated(this);
|
| -
|
| - CreateMessageFilters();
|
| -
|
| - if (run_renderer_in_process()) {
|
| - // Crank up a thread and run the initialization there. With the way that
|
| - // messages flow between the browser and renderer, this thread is required
|
| - // to prevent a deadlock in single-process mode. Since the primordial
|
| - // thread in the renderer process runs the WebKit code and can sometimes
|
| - // make blocking calls to the UI thread (i.e. this thread), they need to run
|
| - // on separate threads.
|
| - in_process_renderer_.reset(new RendererMainThread(channel_id));
|
| -
|
| - base::Thread::Options options;
|
| -#if !defined(TOOLKIT_USES_GTK)
|
| - // In-process plugins require this to be a UI message loop.
|
| - options.message_loop_type = MessageLoop::TYPE_UI;
|
| -#else
|
| - // We can't have multiple UI loops on GTK, so we don't support
|
| - // in-process plugins.
|
| - options.message_loop_type = MessageLoop::TYPE_DEFAULT;
|
| -#endif
|
| - in_process_renderer_->StartWithOptions(options);
|
| -
|
| - OnProcessLaunched(); // Fake a callback that the process is ready.
|
| - } else {
|
| - // Build command line for renderer. We call AppendRendererCommandLine()
|
| - // first so the process type argument will appear first.
|
| - CommandLine* cmd_line = new CommandLine(renderer_path);
|
| - if (!renderer_prefix.empty())
|
| - cmd_line->PrependWrapper(renderer_prefix);
|
| - AppendRendererCommandLine(cmd_line);
|
| - cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id);
|
| -
|
| - // Spawn the child process asynchronously to avoid blocking the UI thread.
|
| - // As long as there's no renderer prefix, we can use the zygote process
|
| - // at this stage.
|
| - child_process_launcher_.reset(new ChildProcessLauncher(
|
| -#if defined(OS_WIN)
|
| - FilePath(),
|
| -#elif defined(OS_POSIX)
|
| - renderer_prefix.empty(),
|
| - base::environment_vector(),
|
| - channel_->TakeClientFileDescriptor(),
|
| -#endif
|
| - cmd_line,
|
| - this));
|
| -
|
| - fast_shutdown_started_ = false;
|
| - }
|
| -
|
| - is_initialized_ = true;
|
| - return true;
|
| -}
|
| -
|
| -void BrowserRenderProcessHost::CreateMessageFilters() {
|
| - scoped_refptr<RenderMessageFilter> render_message_filter(
|
| - new RenderMessageFilter(
|
| - id(),
|
| - PluginService::GetInstance(),
|
| - browser_context(),
|
| - browser_context()->GetRequestContextForRenderProcess(id()),
|
| - widget_helper_));
|
| - channel_->AddFilter(render_message_filter);
|
| -
|
| - ResourceMessageFilter* resource_message_filter = new ResourceMessageFilter(
|
| - id(), ChildProcessInfo::RENDER_PROCESS,
|
| - &browser_context()->GetResourceContext(),
|
| - new RendererURLRequestContextSelector(browser_context(), id()),
|
| - content::GetContentClient()->browser()->GetResourceDispatcherHost());
|
| -
|
| - channel_->AddFilter(resource_message_filter);
|
| - channel_->AddFilter(new AudioInputRendererHost(
|
| - &browser_context()->GetResourceContext()));
|
| - channel_->AddFilter(
|
| - new AudioRendererHost(&browser_context()->GetResourceContext()));
|
| - channel_->AddFilter(
|
| - new VideoCaptureHost(&browser_context()->GetResourceContext()));
|
| - channel_->AddFilter(
|
| - new AppCacheDispatcherHost(browser_context()->GetAppCacheService(),
|
| - id()));
|
| - channel_->AddFilter(new ClipboardMessageFilter());
|
| - channel_->AddFilter(
|
| - new DOMStorageMessageFilter(id(), browser_context()->GetWebKitContext()));
|
| - channel_->AddFilter(
|
| - new IndexedDBDispatcherHost(id(), browser_context()->GetWebKitContext()));
|
| - channel_->AddFilter(
|
| - GeolocationDispatcherHost::New(
|
| - id(), browser_context()->GetGeolocationPermissionContext()));
|
| - channel_->AddFilter(new GpuMessageFilter(id(), widget_helper_.get()));
|
| - channel_->AddFilter(new media_stream::MediaStreamDispatcherHost(
|
| - &browser_context()->GetResourceContext(), id()));
|
| - channel_->AddFilter(new PepperFileMessageFilter(id(), browser_context()));
|
| - channel_->AddFilter(
|
| - new PepperMessageFilter(&browser_context()->GetResourceContext()));
|
| - channel_->AddFilter(new speech_input::SpeechInputDispatcherHost(
|
| - id(), browser_context()->GetRequestContext(),
|
| - browser_context()->GetSpeechInputPreferences()));
|
| - channel_->AddFilter(
|
| - new FileSystemDispatcherHost(browser_context()->GetRequestContext(),
|
| - browser_context()->GetFileSystemContext()));
|
| - channel_->AddFilter(new device_orientation::MessageFilter());
|
| - channel_->AddFilter(
|
| - new BlobMessageFilter(id(), browser_context()->GetBlobStorageContext()));
|
| - channel_->AddFilter(new FileUtilitiesMessageFilter(id()));
|
| - channel_->AddFilter(new MimeRegistryMessageFilter());
|
| - channel_->AddFilter(new DatabaseMessageFilter(
|
| - browser_context()->GetDatabaseTracker()));
|
| -#if defined(OS_MACOSX)
|
| - channel_->AddFilter(new TextInputClientMessageFilter(id()));
|
| -#endif
|
| -
|
| - SocketStreamDispatcherHost* socket_stream_dispatcher_host =
|
| - new SocketStreamDispatcherHost(
|
| - new RendererURLRequestContextSelector(browser_context(), id()),
|
| - &browser_context()->GetResourceContext());
|
| - channel_->AddFilter(socket_stream_dispatcher_host);
|
| -
|
| - channel_->AddFilter(
|
| - new WorkerMessageFilter(
|
| - id(),
|
| - &browser_context()->GetResourceContext(),
|
| - content::GetContentClient()->browser()->GetResourceDispatcherHost(),
|
| - base::Bind(&RenderWidgetHelper::GetNextRoutingID,
|
| - base::Unretained(widget_helper_.get()))));
|
| -
|
| -#if defined(ENABLE_P2P_APIS)
|
| - channel_->AddFilter(new content::P2PSocketDispatcherHost(
|
| - &browser_context()->GetResourceContext()));
|
| -#endif
|
| -
|
| - channel_->AddFilter(new TraceMessageFilter());
|
| - channel_->AddFilter(new ResolveProxyMsgHelper(
|
| - browser_context()->GetRequestContextForRenderProcess(id())));
|
| - channel_->AddFilter(new QuotaDispatcherHost(
|
| - id(), browser_context()->GetQuotaManager(),
|
| - content::GetContentClient()->browser()->CreateQuotaPermissionContext()));
|
| -}
|
| -
|
| -int BrowserRenderProcessHost::GetNextRoutingID() {
|
| - return widget_helper_->GetNextRoutingID();
|
| -}
|
| -
|
| -void BrowserRenderProcessHost::UpdateAndSendMaxPageID(int32 page_id) {
|
| - if (page_id > max_page_id_)
|
| - Send(new ViewMsg_SetNextPageID(page_id + 1));
|
| - UpdateMaxPageID(page_id);
|
| -}
|
| -
|
| -void BrowserRenderProcessHost::CancelResourceRequests(int render_widget_id) {
|
| - widget_helper_->CancelResourceRequests(render_widget_id);
|
| -}
|
| -
|
| -void BrowserRenderProcessHost::CrossSiteSwapOutACK(
|
| - const ViewMsg_SwapOut_Params& params) {
|
| - widget_helper_->CrossSiteSwapOutACK(params);
|
| -}
|
| -
|
| -bool BrowserRenderProcessHost::WaitForUpdateMsg(
|
| - int render_widget_id,
|
| - const base::TimeDelta& max_delay,
|
| - IPC::Message* msg) {
|
| - // The post task to this thread with the process id could be in queue, and we
|
| - // don't want to dispatch a message before then since it will need the handle.
|
| - if (child_process_launcher_.get() && child_process_launcher_->IsStarting())
|
| - return false;
|
| -
|
| - return widget_helper_->WaitForUpdateMsg(render_widget_id, max_delay, msg);
|
| -}
|
| -
|
| -void BrowserRenderProcessHost::ReceivedBadMessage() {
|
| - if (run_renderer_in_process()) {
|
| - // In single process mode it is better if we don't suicide but just
|
| - // crash.
|
| - CHECK(false);
|
| - }
|
| - NOTREACHED();
|
| - base::KillProcess(GetHandle(), content::RESULT_CODE_KILLED_BAD_MESSAGE,
|
| - false);
|
| -}
|
| -
|
| -void BrowserRenderProcessHost::WidgetRestored() {
|
| - // Verify we were properly backgrounded.
|
| - DCHECK_EQ(backgrounded_, (visible_widgets_ == 0));
|
| - visible_widgets_++;
|
| - SetBackgrounded(false);
|
| -}
|
| -
|
| -void BrowserRenderProcessHost::WidgetHidden() {
|
| - // On startup, the browser will call Hide
|
| - if (backgrounded_)
|
| - return;
|
| -
|
| - DCHECK_EQ(backgrounded_, (visible_widgets_ == 0));
|
| - visible_widgets_--;
|
| - DCHECK_GE(visible_widgets_, 0);
|
| - if (visible_widgets_ == 0) {
|
| - DCHECK(!backgrounded_);
|
| - SetBackgrounded(true);
|
| - }
|
| -}
|
| -
|
| -int BrowserRenderProcessHost::VisibleWidgetCount() const {
|
| - return visible_widgets_;
|
| -}
|
| -
|
| -void BrowserRenderProcessHost::AppendRendererCommandLine(
|
| - CommandLine* command_line) const {
|
| - // Pass the process type first, so it shows first in process listings.
|
| - command_line->AppendSwitchASCII(switches::kProcessType,
|
| - switches::kRendererProcess);
|
| -
|
| - if (accessibility_enabled_)
|
| - command_line->AppendSwitch(switches::kEnableAccessibility);
|
| -
|
| - // Now send any options from our own command line we want to propagate.
|
| - const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
|
| - PropagateBrowserCommandLineToRenderer(browser_command_line, command_line);
|
| -
|
| - // Pass on the browser locale.
|
| - const std::string locale =
|
| - content::GetContentClient()->browser()->GetApplicationLocale();
|
| - command_line->AppendSwitchASCII(switches::kLang, locale);
|
| -
|
| - // If we run base::FieldTrials, we want to pass to their state to the
|
| - // renderer so that it can act in accordance with each state, or record
|
| - // histograms relating to the base::FieldTrial states.
|
| - std::string field_trial_states;
|
| - base::FieldTrialList::StatesToString(&field_trial_states);
|
| - if (!field_trial_states.empty()) {
|
| - command_line->AppendSwitchASCII(switches::kForceFieldTestNameAndValue,
|
| - field_trial_states);
|
| - }
|
| -
|
| - content::GetContentClient()->browser()->AppendExtraCommandLineSwitches(
|
| - command_line, id());
|
| -
|
| - // Appending disable-gpu-feature switches due to software rendering list.
|
| - GpuDataManager* gpu_data_manager = GpuDataManager::GetInstance();
|
| - DCHECK(gpu_data_manager);
|
| - gpu_data_manager->AppendRendererCommandLine(command_line);
|
| -}
|
| -
|
| -void BrowserRenderProcessHost::PropagateBrowserCommandLineToRenderer(
|
| - const CommandLine& browser_cmd,
|
| - CommandLine* renderer_cmd) const {
|
| - // Propagate the following switches to the renderer command line (along
|
| - // with any associated values) if present in the browser command line.
|
| - static const char* const kSwitchNames[] = {
|
| - // We propagate the Chrome Frame command line here as well in case the
|
| - // renderer is not run in the sandbox.
|
| - switches::kAuditAllHandles,
|
| - switches::kAuditHandles,
|
| - switches::kChromeFrame,
|
| - switches::kDisable3DAPIs,
|
| - switches::kDisableAcceleratedCompositing,
|
| - switches::kDisableApplicationCache,
|
| - switches::kDisableAudio,
|
| - switches::kDisableBreakpad,
|
| - switches::kDisableDataTransferItems,
|
| - switches::kDisableDatabases,
|
| - switches::kDisableDesktopNotifications,
|
| - switches::kDisableDeviceOrientation,
|
| - switches::kDisableFileSystem,
|
| - switches::kDisableGeolocation,
|
| - switches::kDisableGLMultisampling,
|
| - switches::kDisableGLSLTranslator,
|
| - switches::kDisableGpuDriverBugWorkarounds,
|
| - switches::kDisableGpuVsync,
|
| - switches::kDisableIndexedDatabase,
|
| - switches::kDisableJavaScriptI18NAPI,
|
| - switches::kDisableLocalStorage,
|
| - switches::kDisableLogging,
|
| - switches::kDisableSeccompSandbox,
|
| - switches::kDisableSessionStorage,
|
| - switches::kDisableSharedWorkers,
|
| - switches::kDisableSpeechInput,
|
| - switches::kDisableWebAudio,
|
| - switches::kDisableWebSockets,
|
| - switches::kEnableAccessibilityLogging,
|
| - switches::kEnableDCHECK,
|
| - switches::kEnableGamepad,
|
| - switches::kEnableGPUServiceLogging,
|
| - switches::kEnableGPUClientLogging,
|
| - switches::kEnableLogging,
|
| - switches::kEnableMediaSource,
|
| - switches::kEnableMediaStream,
|
| - switches::kEnableStrictSiteIsolation,
|
| - switches::kDisableFullScreen,
|
| - switches::kEnablePepperTesting,
|
| -#if defined(OS_MACOSX)
|
| - // Allow this to be set when invoking the browser and relayed along.
|
| - switches::kEnableSandboxLogging,
|
| -#endif
|
| - switches::kEnableSeccompSandbox,
|
| - switches::kEnableStatsTable,
|
| - switches::kEnableThreadedCompositing,
|
| - switches::kEnableVideoFullscreen,
|
| - switches::kEnableVideoLogging,
|
| - switches::kEnableVideoTrack,
|
| - switches::kFullMemoryCrashReport,
|
| -#if !defined (GOOGLE_CHROME_BUILD)
|
| - // These are unsupported and not fully tested modes, so don't enable them
|
| - // for official Google Chrome builds.
|
| - switches::kInProcessPlugins,
|
| -#endif // GOOGLE_CHROME_BUILD
|
| - switches::kInProcessWebGL,
|
| - switches::kJavaScriptFlags,
|
| - switches::kLoggingLevel,
|
| - switches::kHighLatencyAudio,
|
| - switches::kNoJsRandomness,
|
| - switches::kNoReferrers,
|
| - switches::kNoSandbox,
|
| - switches::kPlaybackMode,
|
| - switches::kPpapiOutOfProcess,
|
| - switches::kRecordMode,
|
| - switches::kRegisterPepperPlugins,
|
| - switches::kRemoteShellPort,
|
| - switches::kRendererAssertTest,
|
| -#if !defined(OFFICIAL_BUILD)
|
| - switches::kRendererCheckFalseTest,
|
| -#endif // !defined(OFFICIAL_BUILD)
|
| - switches::kRendererCrashTest,
|
| - switches::kRendererStartupDialog,
|
| - switches::kShowPaintRects,
|
| - switches::kSimpleDataSource,
|
| - switches::kTestSandbox,
|
| - switches::kTraceStartup,
|
| - // This flag needs to be propagated to the renderer process for
|
| - // --in-process-webgl.
|
| - switches::kUseGL,
|
| - switches::kUserAgent,
|
| - switches::kV,
|
| - switches::kVideoThreads,
|
| - switches::kVModule,
|
| - switches::kWebCoreLogChannels,
|
| - };
|
| - renderer_cmd->CopySwitchesFrom(browser_cmd, kSwitchNames,
|
| - arraysize(kSwitchNames));
|
| -
|
| - // Disable databases in incognito mode.
|
| - if (browser_context()->IsOffTheRecord() &&
|
| - !browser_cmd.HasSwitch(switches::kDisableDatabases)) {
|
| - renderer_cmd->AppendSwitch(switches::kDisableDatabases);
|
| - }
|
| -}
|
| -
|
| -base::ProcessHandle BrowserRenderProcessHost::GetHandle() {
|
| - // child_process_launcher_ is null either because we're in single process
|
| - // mode, we have done fast termination, or the process has crashed.
|
| - if (run_renderer_in_process() || !child_process_launcher_.get())
|
| - return base::Process::Current().handle();
|
| -
|
| - if (child_process_launcher_->IsStarting())
|
| - return base::kNullProcessHandle;
|
| -
|
| - return child_process_launcher_->GetHandle();
|
| -}
|
| -
|
| -bool BrowserRenderProcessHost::FastShutdownIfPossible() {
|
| - if (run_renderer_in_process())
|
| - return false; // Single process mode can't do fast shutdown.
|
| -
|
| - if (!content::GetContentClient()->browser()->IsFastShutdownPossible())
|
| - return false;
|
| -
|
| - if (!child_process_launcher_.get() ||
|
| - child_process_launcher_->IsStarting() ||
|
| - !GetHandle())
|
| - return false; // Render process hasn't started or is probably crashed.
|
| -
|
| - // Test if there's an unload listener.
|
| - // NOTE: It's possible that an onunload listener may be installed
|
| - // while we're shutting down, so there's a small race here. Given that
|
| - // the window is small, it's unlikely that the web page has much
|
| - // state that will be lost by not calling its unload handlers properly.
|
| - if (!sudden_termination_allowed())
|
| - return false;
|
| -
|
| - // Store the handle before it gets changed.
|
| - base::ProcessHandle handle = GetHandle();
|
| - ProcessDied(handle, base::TERMINATION_STATUS_NORMAL_TERMINATION, 0, false);
|
| - fast_shutdown_started_ = true;
|
| - return true;
|
| -}
|
| -
|
| -void BrowserRenderProcessHost::DumpHandles() {
|
| -#if defined(OS_WIN)
|
| - Send(new ChildProcessMsg_DumpHandles());
|
| - return;
|
| -#endif
|
| -
|
| - NOTIMPLEMENTED();
|
| -}
|
| -
|
| -// This is a platform specific function for mapping a transport DIB given its id
|
| -TransportDIB* BrowserRenderProcessHost::MapTransportDIB(
|
| - TransportDIB::Id dib_id) {
|
| -#if defined(OS_WIN)
|
| - // On Windows we need to duplicate the handle from the remote process
|
| - HANDLE section = chrome::GetSectionFromProcess(
|
| - dib_id.handle, GetHandle(), false /* read write */);
|
| - return TransportDIB::Map(section);
|
| -#elif defined(OS_MACOSX)
|
| - // On OSX, the browser allocates all DIBs and keeps a file descriptor around
|
| - // for each.
|
| - return widget_helper_->MapTransportDIB(dib_id);
|
| -#elif defined(OS_POSIX)
|
| - return TransportDIB::Map(dib_id.shmkey);
|
| -#endif // defined(OS_POSIX)
|
| -}
|
| -
|
| -TransportDIB* BrowserRenderProcessHost::GetTransportDIB(
|
| - TransportDIB::Id dib_id) {
|
| - if (!TransportDIB::is_valid_id(dib_id))
|
| - return NULL;
|
| -
|
| - const std::map<TransportDIB::Id, TransportDIB*>::iterator
|
| - i = cached_dibs_.find(dib_id);
|
| - if (i != cached_dibs_.end()) {
|
| - cached_dibs_cleaner_.Reset();
|
| - return i->second;
|
| - }
|
| -
|
| - TransportDIB* dib = MapTransportDIB(dib_id);
|
| - if (!dib)
|
| - return NULL;
|
| -
|
| - if (cached_dibs_.size() >= MAX_MAPPED_TRANSPORT_DIBS) {
|
| - // Clean a single entry from the cache
|
| - std::map<TransportDIB::Id, TransportDIB*>::iterator smallest_iterator;
|
| - size_t smallest_size = std::numeric_limits<size_t>::max();
|
| -
|
| - for (std::map<TransportDIB::Id, TransportDIB*>::iterator
|
| - i = cached_dibs_.begin(); i != cached_dibs_.end(); ++i) {
|
| - if (i->second->size() <= smallest_size) {
|
| - smallest_iterator = i;
|
| - smallest_size = i->second->size();
|
| - }
|
| - }
|
| -
|
| - delete smallest_iterator->second;
|
| - cached_dibs_.erase(smallest_iterator);
|
| - }
|
| -
|
| - cached_dibs_[dib_id] = dib;
|
| - cached_dibs_cleaner_.Reset();
|
| - return dib;
|
| -}
|
| -
|
| -void BrowserRenderProcessHost::ClearTransportDIBCache() {
|
| - STLDeleteContainerPairSecondPointers(
|
| - cached_dibs_.begin(), cached_dibs_.end());
|
| - cached_dibs_.clear();
|
| -}
|
| -
|
| -void BrowserRenderProcessHost::SetCompositingSurface(
|
| - int render_widget_id,
|
| - gfx::PluginWindowHandle compositing_surface) {
|
| - widget_helper_->SetCompositingSurface(render_widget_id, compositing_surface);
|
| -}
|
| -
|
| -bool BrowserRenderProcessHost::Send(IPC::Message* msg) {
|
| - if (!channel_.get()) {
|
| - if (!is_initialized_) {
|
| - queued_messages_.push(msg);
|
| - return true;
|
| - } else {
|
| - delete msg;
|
| - return false;
|
| - }
|
| - }
|
| -
|
| - if (child_process_launcher_.get() && child_process_launcher_->IsStarting()) {
|
| - queued_messages_.push(msg);
|
| - return true;
|
| - }
|
| -
|
| - return channel_->Send(msg);
|
| -}
|
| -
|
| -bool BrowserRenderProcessHost::OnMessageReceived(const IPC::Message& msg) {
|
| - // If we're about to be deleted, or have initiated the fast shutdown sequence,
|
| - // we ignore incoming messages.
|
| -
|
| - if (deleting_soon_ || fast_shutdown_started_)
|
| - return false;
|
| -
|
| - mark_child_process_activity_time();
|
| - if (msg.routing_id() == MSG_ROUTING_CONTROL) {
|
| - // Dispatch control messages.
|
| - bool msg_is_ok = true;
|
| - IPC_BEGIN_MESSAGE_MAP_EX(BrowserRenderProcessHost, msg, msg_is_ok)
|
| - IPC_MESSAGE_HANDLER(ChildProcessHostMsg_ShutdownRequest,
|
| - OnShutdownRequest)
|
| - IPC_MESSAGE_HANDLER(ChildProcessHostMsg_DumpHandlesDone,
|
| - OnDumpHandlesDone)
|
| - IPC_MESSAGE_HANDLER(ViewHostMsg_SuddenTerminationChanged,
|
| - SuddenTerminationChanged)
|
| - IPC_MESSAGE_HANDLER(ViewHostMsg_UserMetricsRecordAction,
|
| - OnUserMetricsRecordAction)
|
| - IPC_MESSAGE_HANDLER(ViewHostMsg_RevealFolderInOS, OnRevealFolderInOS)
|
| - IPC_MESSAGE_HANDLER(ViewHostMsg_SavedPageAsMHTML, OnSavedPageAsMHTML)
|
| - IPC_MESSAGE_UNHANDLED_ERROR()
|
| - IPC_END_MESSAGE_MAP_EX()
|
| -
|
| - if (!msg_is_ok) {
|
| - // The message had a handler, but its de-serialization failed.
|
| - // We consider this a capital crime. Kill the renderer if we have one.
|
| - LOG(ERROR) << "bad message " << msg.type() << " terminating renderer.";
|
| - UserMetrics::RecordAction(UserMetricsAction("BadMessageTerminate_BRPH"));
|
| - ReceivedBadMessage();
|
| - }
|
| - return true;
|
| - }
|
| -
|
| - // Dispatch incoming messages to the appropriate RenderView/WidgetHost.
|
| - IPC::Channel::Listener* listener = GetListenerByID(msg.routing_id());
|
| - if (!listener) {
|
| - if (msg.is_sync()) {
|
| - // The listener has gone away, so we must respond or else the caller will
|
| - // hang waiting for a reply.
|
| - IPC::Message* reply = IPC::SyncMessage::GenerateReply(&msg);
|
| - reply->set_reply_error();
|
| - Send(reply);
|
| - }
|
| - return true;
|
| - }
|
| - return listener->OnMessageReceived(msg);
|
| -}
|
| -
|
| -void BrowserRenderProcessHost::OnChannelConnected(int32 peer_pid) {
|
| -#if defined(IPC_MESSAGE_LOG_ENABLED)
|
| - Send(new ChildProcessMsg_SetIPCLoggingEnabled(
|
| - IPC::Logging::GetInstance()->Enabled()));
|
| -#endif
|
| -
|
| - // Make sure the child checks with us before exiting, so that we do not try
|
| - // to schedule a new navigation in a swapped out and exiting renderer.
|
| - Send(new ChildProcessMsg_AskBeforeShutdown());
|
| -}
|
| -
|
| -void BrowserRenderProcessHost::OnChannelError() {
|
| - if (!channel_.get())
|
| - return;
|
| -
|
| - // Store the handle before it gets changed.
|
| - base::ProcessHandle handle = GetHandle();
|
| -
|
| - // child_process_launcher_ can be NULL in single process mode or if fast
|
| - // termination happened.
|
| - int exit_code = 0;
|
| - base::TerminationStatus status =
|
| - child_process_launcher_.get() ?
|
| - child_process_launcher_->GetChildTerminationStatus(&exit_code) :
|
| - base::TERMINATION_STATUS_NORMAL_TERMINATION;
|
| -
|
| -#if defined(OS_WIN)
|
| - if (!run_renderer_in_process()) {
|
| - if (status == base::TERMINATION_STATUS_STILL_RUNNING) {
|
| - HANDLE process = child_process_launcher_->GetHandle();
|
| - child_process_watcher_.StartWatching(
|
| - new base::WaitableEvent(process), this);
|
| - return;
|
| - }
|
| - }
|
| -#endif
|
| - ProcessDied(handle, status, exit_code, false);
|
| -}
|
| -
|
| -// Called when the renderer process handle has been signaled.
|
| -void BrowserRenderProcessHost::OnWaitableEventSignaled(
|
| - base::WaitableEvent* waitable_event) {
|
| -#if defined (OS_WIN)
|
| - base::ProcessHandle handle = GetHandle();
|
| - int exit_code = 0;
|
| - base::TerminationStatus status =
|
| - base::GetTerminationStatus(waitable_event->Release(), &exit_code);
|
| - delete waitable_event;
|
| - ProcessDied(handle, status, exit_code, true);
|
| -#endif
|
| -}
|
| -
|
| -void BrowserRenderProcessHost::ProcessDied(base::ProcessHandle handle,
|
| - base::TerminationStatus status,
|
| - int exit_code,
|
| - bool was_alive) {
|
| - // Our child process has died. If we didn't expect it, it's a crash.
|
| - // In any case, we need to let everyone know it's gone.
|
| - // The OnChannelError notification can fire multiple times due to nested sync
|
| - // calls to a renderer. If we don't have a valid channel here it means we
|
| - // already handled the error.
|
| -
|
| - RendererClosedDetails details(handle, status, exit_code, was_alive);
|
| - content::NotificationService::current()->Notify(
|
| - content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
|
| - content::Source<RenderProcessHost>(this),
|
| - content::Details<RendererClosedDetails>(&details));
|
| -
|
| - child_process_launcher_.reset();
|
| - channel_.reset();
|
| -
|
| - IDMap<IPC::Channel::Listener>::iterator iter(&listeners_);
|
| - while (!iter.IsAtEnd()) {
|
| - iter.GetCurrentValue()->OnMessageReceived(
|
| - ViewHostMsg_RenderViewGone(iter.GetCurrentKey(),
|
| - static_cast<int>(status),
|
| - exit_code));
|
| - iter.Advance();
|
| - }
|
| -
|
| - ClearTransportDIBCache();
|
| -
|
| - // this object is not deleted at this point and may be reused later.
|
| - // TODO(darin): clean this up
|
| -}
|
| -
|
| -void BrowserRenderProcessHost::OnShutdownRequest() {
|
| - // Don't shutdown if there are pending RenderViews being swapped back in.
|
| - if (pending_views_)
|
| - return;
|
| -
|
| - // Notify any tabs that might have swapped out renderers from this process.
|
| - // They should not attempt to swap them back in.
|
| - content::NotificationService::current()->Notify(
|
| - content::NOTIFICATION_RENDERER_PROCESS_CLOSING,
|
| - content::Source<RenderProcessHost>(this),
|
| - content::NotificationService::NoDetails());
|
| -
|
| - Send(new ChildProcessMsg_Shutdown());
|
| -}
|
| -
|
| -void BrowserRenderProcessHost::OnDumpHandlesDone() {
|
| - Cleanup();
|
| -}
|
| -
|
| -void BrowserRenderProcessHost::SuddenTerminationChanged(bool enabled) {
|
| - set_sudden_termination_allowed(enabled);
|
| -}
|
| -
|
| -void BrowserRenderProcessHost::SetBackgrounded(bool backgrounded) {
|
| - // Note: we always set the backgrounded_ value. If the process is NULL
|
| - // (and hence hasn't been created yet), we will set the process priority
|
| - // later when we create the process.
|
| - backgrounded_ = backgrounded;
|
| - if (!child_process_launcher_.get() || child_process_launcher_->IsStarting())
|
| - return;
|
| -
|
| -#if defined(OS_WIN)
|
| - // The cbstext.dll loads as a global GetMessage hook in the browser process
|
| - // and intercepts/unintercepts the kernel32 API SetPriorityClass in a
|
| - // background thread. If the UI thread invokes this API just when it is
|
| - // intercepted the stack is messed up on return from the interceptor
|
| - // which causes random crashes in the browser process. Our hack for now
|
| - // is to not invoke the SetPriorityClass API if the dll is loaded.
|
| - if (GetModuleHandle(L"cbstext.dll"))
|
| - return;
|
| -#endif // OS_WIN
|
| -
|
| - child_process_launcher_->SetProcessBackgrounded(backgrounded);
|
| -}
|
| -
|
| -void BrowserRenderProcessHost::OnProcessLaunched() {
|
| - // No point doing anything, since this object will be destructed soon. We
|
| - // especially don't want to send the RENDERER_PROCESS_CREATED notification,
|
| - // since some clients might expect a RENDERER_PROCESS_TERMINATED afterwards to
|
| - // properly cleanup.
|
| - if (deleting_soon_)
|
| - return;
|
| -
|
| - if (child_process_launcher_.get()) {
|
| - if (!child_process_launcher_->GetHandle()) {
|
| - OnChannelError();
|
| - return;
|
| - }
|
| -
|
| - child_process_launcher_->SetProcessBackgrounded(backgrounded_);
|
| - }
|
| -
|
| - if (max_page_id_ != -1)
|
| - Send(new ViewMsg_SetNextPageID(max_page_id_ + 1));
|
| -
|
| - // NOTE: This needs to be before sending queued messages because
|
| - // ExtensionService uses this notification to initialize the renderer process
|
| - // with state that must be there before any JavaScript executes.
|
| - //
|
| - // The queued messages contain such things as "navigate". If this notification
|
| - // was after, we can end up executing JavaScript before the initialization
|
| - // happens.
|
| - content::NotificationService::current()->Notify(
|
| - content::NOTIFICATION_RENDERER_PROCESS_CREATED,
|
| - content::Source<RenderProcessHost>(this),
|
| - content::NotificationService::NoDetails());
|
| -
|
| - while (!queued_messages_.empty()) {
|
| - Send(queued_messages_.front());
|
| - queued_messages_.pop();
|
| - }
|
| -}
|
| -
|
| -void BrowserRenderProcessHost::OnUserMetricsRecordAction(
|
| - const std::string& action) {
|
| - UserMetrics::RecordComputedAction(action);
|
| -}
|
| -
|
| -void BrowserRenderProcessHost::OnRevealFolderInOS(const FilePath& path) {
|
| - // Only honor the request if appropriate persmissions are granted.
|
| - if (ChildProcessSecurityPolicy::GetInstance()->CanReadFile(id(), path))
|
| - content::GetContentClient()->browser()->OpenItem(path);
|
| -}
|
| -
|
| -void BrowserRenderProcessHost::OnSavedPageAsMHTML(int job_id, int64 data_size) {
|
| - content::GetContentClient()->browser()->GetMHTMLGenerationManager()->
|
| - MHTMLGenerated(job_id, data_size);
|
| -}
|
|
|