summaryrefslogtreecommitdiffstats
path: root/chromium/content/child/child_thread.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/content/child/child_thread.cc')
-rw-r--r--chromium/content/child/child_thread.cc192
1 files changed, 145 insertions, 47 deletions
diff --git a/chromium/content/child/child_thread.cc b/chromium/content/child/child_thread.cc
index 5b54ee041f9..3222b4167a1 100644
--- a/chromium/content/child/child_thread.cc
+++ b/chromium/content/child/child_thread.cc
@@ -4,16 +4,22 @@
#include "content/child/child_thread.h"
+#include <signal.h>
+
#include <string>
#include "base/allocator/allocator_extension.h"
#include "base/base_switches.h"
+#include "base/basictypes.h"
#include "base/command_line.h"
#include "base/debug/leak_annotations.h"
#include "base/lazy_instance.h"
+#include "base/logging.h"
#include "base/message_loop/message_loop.h"
+#include "base/message_loop/timer_slack.h"
#include "base/process/kill.h"
#include "base/process/process_handle.h"
+#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/synchronization/condition_variable.h"
#include "base/synchronization/lock.h"
@@ -23,7 +29,10 @@
#include "content/child/child_histogram_message_filter.h"
#include "content/child/child_process.h"
#include "content/child/child_resource_message_filter.h"
+#include "content/child/child_shared_bitmap_manager.h"
#include "content/child/fileapi/file_system_dispatcher.h"
+#include "content/child/fileapi/webfilesystem_impl.h"
+#include "content/child/mojo/mojo_application.h"
#include "content/child/power_monitor_broadcast_source.h"
#include "content/child/quota_dispatcher.h"
#include "content/child/quota_message_filter.h"
@@ -64,16 +73,55 @@ base::LazyInstance<base::ThreadLocalPointer<ChildThread> > g_lazy_tls =
// plugins), PluginThread has EnsureTerminateMessageFilter.
#if defined(OS_POSIX)
-class SuicideOnChannelErrorFilter : public IPC::ChannelProxy::MessageFilter {
+// TODO(earthdok): Re-enable on CrOS http://crbug.com/360622
+#if (defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || \
+ defined(THREAD_SANITIZER)) && !defined(OS_CHROMEOS)
+// A thread delegate that waits for |duration| and then exits the process with
+// _exit(0).
+class WaitAndExitDelegate : public base::PlatformThread::Delegate {
+ public:
+ explicit WaitAndExitDelegate(base::TimeDelta duration)
+ : duration_(duration) {}
+ virtual ~WaitAndExitDelegate() OVERRIDE {}
+
+ virtual void ThreadMain() OVERRIDE {
+ base::PlatformThread::Sleep(duration_);
+ _exit(0);
+ }
+
+ private:
+ const base::TimeDelta duration_;
+ DISALLOW_COPY_AND_ASSIGN(WaitAndExitDelegate);
+};
+
+bool CreateWaitAndExitThread(base::TimeDelta duration) {
+ scoped_ptr<WaitAndExitDelegate> delegate(new WaitAndExitDelegate(duration));
+
+ const bool thread_created =
+ base::PlatformThread::CreateNonJoinable(0, delegate.get());
+ if (!thread_created)
+ return false;
+
+ // A non joinable thread has been created. The thread will either terminate
+ // the process or will be terminated by the process. Therefore, keep the
+ // delegate object alive for the lifetime of the process.
+ WaitAndExitDelegate* leaking_delegate = delegate.release();
+ ANNOTATE_LEAKING_OBJECT_PTR(leaking_delegate);
+ ignore_result(leaking_delegate);
+ return true;
+}
+#endif
+
+class SuicideOnChannelErrorFilter : public IPC::MessageFilter {
public:
- // IPC::ChannelProxy::MessageFilter
+ // IPC::MessageFilter
virtual void OnChannelError() OVERRIDE {
// For renderer/worker processes:
// On POSIX, at least, one can install an unload handler which loops
// forever and leave behind a renderer process which eats 100% CPU forever.
//
// This is because the terminate signals (ViewMsg_ShouldClose and the error
- // from the IPC channel) are routed to the main message loop but never
+ // from the IPC sender) are routed to the main message loop but never
// processed (because that message loop is stuck in V8).
//
// One could make the browser SIGKILL the renderers, but that leaves open a
@@ -81,23 +129,23 @@ class SuicideOnChannelErrorFilter : public IPC::ChannelProxy::MessageFilter {
// the browser because "it's stuck") will leave behind a process eating all
// the CPU.
//
- // So, we install a filter on the channel so that we can process this event
+ // So, we install a filter on the sender so that we can process this event
// here and kill the process.
- if (CommandLine::ForCurrentProcess()->
- HasSwitch(switches::kChildCleanExit)) {
- // If clean exit is requested, we want to kill this process after giving
- // it 60 seconds to run exit handlers. Exit handlers may including ones
- // that write profile data to disk (which happens under profile collection
- // mode).
- alarm(60);
+ // TODO(earthdok): Re-enable on CrOS http://crbug.com/360622
+#if (defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || \
+ defined(THREAD_SANITIZER)) && !defined(OS_CHROMEOS)
+ // Some sanitizer tools rely on exit handlers (e.g. to run leak detection,
+ // or dump code coverage data to disk). Instead of exiting the process
+ // immediately, we give it 60 seconds to run exit handlers.
+ CHECK(CreateWaitAndExitThread(base::TimeDelta::FromSeconds(60)));
#if defined(LEAK_SANITIZER)
- // Invoke LeakSanitizer early to avoid detecting shutdown-only leaks. If
- // leaks are found, the process will exit here.
- __lsan_do_leak_check();
+ // Invoke LeakSanitizer early to avoid detecting shutdown-only leaks. If
+ // leaks are found, the process will exit here.
+ __lsan_do_leak_check();
+#endif
+#else
+ _exit(0);
#endif
- } else {
- _exit(0);
- }
}
protected:
@@ -118,7 +166,10 @@ base::LazyInstance<base::Lock> g_lazy_child_thread_lock =
// doesn't handle the case. Thus, we need our own class here.
struct CondVarLazyInstanceTraits {
static const bool kRegisterOnExit = true;
- static const bool kAllowedToAccessOnNonjoinableThread ALLOW_UNUSED = false;
+#ifndef NDEBUG
+ static const bool kAllowedToAccessOnNonjoinableThread = false;
+#endif
+
static base::ConditionVariable* New(void* instance) {
return new (instance) base::ConditionVariable(
g_lazy_child_thread_lock.Pointer());
@@ -141,8 +192,17 @@ void QuitMainThreadMessageLoop() {
} // namespace
+ChildThread::ChildThreadMessageRouter::ChildThreadMessageRouter(
+ IPC::Sender* sender)
+ : sender_(sender) {}
+
+bool ChildThread::ChildThreadMessageRouter::Send(IPC::Message* msg) {
+ return sender_->Send(msg);
+}
+
ChildThread::ChildThread()
- : channel_connected_factory_(this),
+ : router_(this),
+ channel_connected_factory_(this),
in_browser_process_(false) {
channel_name_ = CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
switches::kProcessChannelID);
@@ -151,6 +211,7 @@ ChildThread::ChildThread()
ChildThread::ChildThread(const std::string& channel_name)
: channel_name_(channel_name),
+ router_(this),
channel_connected_factory_(this),
in_browser_process_(true) {
Init();
@@ -166,18 +227,20 @@ void ChildThread::Init() {
// the logger, and the logger does not like being created on the IO thread.
IPC::Logging::GetInstance();
#endif
- channel_.reset(
- new IPC::SyncChannel(channel_name_,
- IPC::Channel::MODE_CLIENT,
- this,
- ChildProcess::current()->io_message_loop_proxy(),
- true,
- ChildProcess::current()->GetShutDownEvent()));
+ channel_ =
+ IPC::SyncChannel::Create(channel_name_,
+ IPC::Channel::MODE_CLIENT,
+ this,
+ ChildProcess::current()->io_message_loop_proxy(),
+ true,
+ ChildProcess::current()->GetShutDownEvent());
#ifdef IPC_MESSAGE_LOG_ENABLED
if (!in_browser_process_)
IPC::Logging::GetInstance()->SetIPCSender(this);
#endif
+ mojo_application_.reset(new MojoApplication(this));
+
sync_message_filter_ =
new IPC::SyncMessageFilter(ChildProcess::current()->GetShutDownEvent());
thread_safe_sender_ = new ThreadSafeSender(
@@ -204,12 +267,17 @@ void ChildThread::Init() {
channel_->AddFilter(histogram_message_filter_.get());
channel_->AddFilter(sync_message_filter_.get());
- channel_->AddFilter(new tracing::ChildTraceMessageFilter(
- ChildProcess::current()->io_message_loop_proxy()));
channel_->AddFilter(resource_message_filter_.get());
channel_->AddFilter(quota_message_filter_->GetFilter());
channel_->AddFilter(service_worker_message_filter_->GetFilter());
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess)) {
+ // In single process mode, browser-side tracing will cover the whole
+ // process including renderers.
+ channel_->AddFilter(new tracing::ChildTraceMessageFilter(
+ ChildProcess::current()->io_message_loop_proxy()));
+ }
+
// In single process mode we may already have a power monitor
if (!base::PowerMonitor::Get()) {
scoped_ptr<PowerMonitorBroadcastSource> power_monitor_source(
@@ -227,11 +295,21 @@ void ChildThread::Init() {
channel_->AddFilter(new SuicideOnChannelErrorFilter());
#endif
+ int connection_timeout = kConnectionTimeoutS;
+ std::string connection_override =
+ CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kIPCConnectionTimeout);
+ if (!connection_override.empty()) {
+ int temp;
+ if (base::StringToInt(connection_override, &temp))
+ connection_timeout = temp;
+ }
+
base::MessageLoop::current()->PostDelayedTask(
FROM_HERE,
base::Bind(&ChildThread::EnsureConnected,
channel_connected_factory_.GetWeakPtr()),
- base::TimeDelta::FromSeconds(kConnectionTimeoutS));
+ base::TimeDelta::FromSeconds(connection_timeout));
#if defined(OS_ANDROID)
{
@@ -250,6 +328,9 @@ void ChildThread::Init() {
::HeapProfilerStop,
::GetHeapProfile));
#endif
+
+ shared_bitmap_manager_.reset(
+ new ChildSharedBitmapManager(thread_safe_sender()));
}
ChildThread::~ChildThread() {
@@ -277,6 +358,7 @@ void ChildThread::Shutdown() {
// safely shutdown blink in their Shutdown implementation.
file_system_dispatcher_.reset();
quota_dispatcher_.reset();
+ WebFileSystemImpl::DeleteThreadSpecificInstance();
}
void ChildThread::OnChannelConnected(int32 peer_pid) {
@@ -288,6 +370,15 @@ void ChildThread::OnChannelError() {
base::MessageLoop::current()->Quit();
}
+void ChildThread::ConnectToService(
+ const mojo::String& service_url,
+ const mojo::String& service_name,
+ mojo::ScopedMessagePipeHandle message_pipe,
+ const mojo::String& requestor_url) {
+ // By default, we don't expect incoming connections.
+ NOTREACHED();
+}
+
bool ChildThread::Send(IPC::Message* msg) {
DCHECK(base::MessageLoop::current() == message_loop());
if (!channel_) {
@@ -298,21 +389,9 @@ bool ChildThread::Send(IPC::Message* msg) {
return channel_->Send(msg);
}
-void ChildThread::AddRoute(int32 routing_id, IPC::Listener* listener) {
- DCHECK(base::MessageLoop::current() == message_loop());
-
- router_.AddRoute(routing_id, listener);
-}
-
-void ChildThread::RemoveRoute(int32 routing_id) {
+MessageRouter* ChildThread::GetRouter() {
DCHECK(base::MessageLoop::current() == message_loop());
-
- router_.RemoveRoute(routing_id);
-}
-
-webkit_glue::ResourceLoaderBridge* ChildThread::CreateBridge(
- const webkit_glue::ResourceLoaderBridge::RequestInfo& request_info) {
- return resource_dispatcher()->CreateBridge(request_info);
+ return &router_;
}
base::SharedMemory* ChildThread::AllocateSharedMemory(size_t buf_size) {
@@ -355,6 +434,9 @@ base::SharedMemory* ChildThread::AllocateSharedMemory(
}
bool ChildThread::OnMessageReceived(const IPC::Message& msg) {
+ if (mojo_application_->OnMessageReceived(msg))
+ return true;
+
// Resource responses are sent to the resource dispatcher.
if (resource_dispatcher_->OnMessageReceived(msg))
return true;
@@ -377,6 +459,8 @@ bool ChildThread::OnMessageReceived(const IPC::Message& msg) {
IPC_MESSAGE_HANDLER(ChildProcessMsg_GetChildProfilerData,
OnGetChildProfilerData)
IPC_MESSAGE_HANDLER(ChildProcessMsg_DumpHandles, OnDumpHandles)
+ IPC_MESSAGE_HANDLER(ChildProcessMsg_SetProcessBackgrounded,
+ OnProcessBackgrounded)
#if defined(USE_TCMALLOC)
IPC_MESSAGE_HANDLER(ChildProcessMsg_GetTcmallocStats, OnGetTcmallocStats)
#endif
@@ -429,10 +513,9 @@ void ChildThread::OnDumpHandles() {
switches::kAuditAllHandles)));
handle_enum->EnumerateHandles();
Send(new ChildProcessHostMsg_DumpHandlesDone);
- return;
-#endif
-
+#else
NOTIMPLEMENTED();
+#endif
}
#if defined(USE_TCMALLOC)
@@ -464,7 +547,6 @@ void ChildThread::ShutdownThread() {
g_child_thread->message_loop()->PostTask(
FROM_HERE, base::Bind(&QuitMainThreadMessageLoop));
}
-
#endif
void ChildThread::OnProcessFinalRelease() {
@@ -487,4 +569,20 @@ void ChildThread::EnsureConnected() {
base::KillProcess(base::GetCurrentProcessHandle(), 0, false);
}
+void ChildThread::OnProcessBackgrounded(bool background) {
+ // Set timer slack to maximum on main thread when in background.
+ base::TimerSlack timer_slack = base::TIMER_SLACK_NONE;
+ if (background)
+ timer_slack = base::TIMER_SLACK_MAXIMUM;
+ base::MessageLoop::current()->SetTimerSlack(timer_slack);
+
+#ifdef OS_WIN
+ // Windows Vista+ has a fancy process backgrounding mode that can only be set
+ // from within the process.
+ // TODO(wfh) Do not set background from within process until the issue with
+ // white tabs is resolved. See http://crbug.com/398103.
+ // base::Process::Current().SetProcessBackgrounded(background);
+#endif // OS_WIN
+}
+
} // namespace content