#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"
#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"
#include "ipc/ipc_switches.h"
#include "ipc/ipc_sync_channel.h"
#include "ipc/ipc_sync_message_filter.h"
-#include "webkit/child/resource_loader_bridge.h"
#if defined(OS_WIN)
#include "content/common/handle_enumerator_win.h"
// plugins), PluginThread has EnsureTerminateMessageFilter.
#if defined(OS_POSIX)
-// A thread delegate that waits for |duration| and then signals the process
-// with SIGALRM.
+// 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)
virtual void ThreadMain() OVERRIDE {
base::PlatformThread::Sleep(duration_);
- // This used to be implemented with alarm(2). Make sure to not break
- // anything that requires the process being signaled.
- CHECK_EQ(0, raise(SIGALRM));
-
- base::PlatformThread::Sleep((base::TimeDelta::FromSeconds(10)));
- // If something erroneously blocked SIGALRM, this will trigger.
- NOTREACHED();
_exit(0);
}
DISALLOW_COPY_AND_ASSIGN(WaitAndExitDelegate);
};
-// This is similar to using alarm(2), except it will spawn a thread
-// which will sleep for |duration| before raising SIGALRM.
-bool CreateAlarmThread(base::TimeDelta duration) {
+bool CreateWaitAndExitThread(base::TimeDelta duration) {
scoped_ptr<WaitAndExitDelegate> delegate(new WaitAndExitDelegate(duration));
- const bool thread_created = base::PlatformThread::CreateNonJoinable(
- 0 /* stack_size */, delegate.get());
+ const bool thread_created =
+ base::PlatformThread::CreateNonJoinable(0, delegate.get());
if (!thread_created)
return false;
ignore_result(leaking_delegate);
return true;
}
+#endif
-class SuicideOnChannelErrorFilter : public IPC::ChannelProxy::MessageFilter {
+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
// 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).
- CHECK(CreateAlarmThread(base::TimeDelta::FromSeconds(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:
// 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(
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(
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)
{
// safely shutdown blink in their Shutdown implementation.
file_system_dispatcher_.reset();
quota_dispatcher_.reset();
+ WebFileSystemImpl::DeleteThreadSpecificInstance();
}
void ChildThread::OnChannelConnected(int32 peer_pid) {
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_) {
return &router_;
}
-webkit_glue::ResourceLoaderBridge* ChildThread::CreateBridge(
- const RequestInfo& request_info) {
- return resource_dispatcher()->CreateBridge(request_info);
-}
-
base::SharedMemory* ChildThread::AllocateSharedMemory(size_t buf_size) {
return AllocateSharedMemory(buf_size, this);
}
}
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;
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
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