1// Copyright (c) 2012 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#include "content/child/child_thread.h" 6 7#include <string> 8 9#include "base/allocator/allocator_extension.h" 10#include "base/base_switches.h" 11#include "base/command_line.h" 12#include "base/debug/leak_annotations.h" 13#include "base/lazy_instance.h" 14#include "base/message_loop/message_loop.h" 15#include "base/process/kill.h" 16#include "base/process/process_handle.h" 17#include "base/strings/string_util.h" 18#include "base/synchronization/condition_variable.h" 19#include "base/synchronization/lock.h" 20#include "base/threading/thread_local.h" 21#include "base/tracked_objects.h" 22#include "components/tracing/child_trace_message_filter.h" 23#include "content/child/child_histogram_message_filter.h" 24#include "content/child/child_process.h" 25#include "content/child/child_resource_message_filter.h" 26#include "content/child/fileapi/file_system_dispatcher.h" 27#include "content/child/power_monitor_broadcast_source.h" 28#include "content/child/quota_dispatcher.h" 29#include "content/child/quota_message_filter.h" 30#include "content/child/resource_dispatcher.h" 31#include "content/child/service_worker/service_worker_dispatcher.h" 32#include "content/child/service_worker/service_worker_message_filter.h" 33#include "content/child/socket_stream_dispatcher.h" 34#include "content/child/thread_safe_sender.h" 35#include "content/child/websocket_dispatcher.h" 36#include "content/common/child_process_messages.h" 37#include "content/public/common/content_switches.h" 38#include "ipc/ipc_logging.h" 39#include "ipc/ipc_switches.h" 40#include "ipc/ipc_sync_channel.h" 41#include "ipc/ipc_sync_message_filter.h" 42 43#if defined(OS_WIN) 44#include "content/common/handle_enumerator_win.h" 45#endif 46 47#if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED) 48#include "third_party/tcmalloc/chromium/src/gperftools/heap-profiler.h" 49#endif 50 51using tracked_objects::ThreadData; 52 53namespace content { 54namespace { 55 56// How long to wait for a connection to the browser process before giving up. 57const int kConnectionTimeoutS = 15; 58 59base::LazyInstance<base::ThreadLocalPointer<ChildThread> > g_lazy_tls = 60 LAZY_INSTANCE_INITIALIZER; 61 62// This isn't needed on Windows because there the sandbox's job object 63// terminates child processes automatically. For unsandboxed processes (i.e. 64// plugins), PluginThread has EnsureTerminateMessageFilter. 65#if defined(OS_POSIX) 66 67class SuicideOnChannelErrorFilter : public IPC::ChannelProxy::MessageFilter { 68 public: 69 // IPC::ChannelProxy::MessageFilter 70 virtual void OnChannelError() OVERRIDE { 71 // For renderer/worker processes: 72 // On POSIX, at least, one can install an unload handler which loops 73 // forever and leave behind a renderer process which eats 100% CPU forever. 74 // 75 // This is because the terminate signals (ViewMsg_ShouldClose and the error 76 // from the IPC channel) are routed to the main message loop but never 77 // processed (because that message loop is stuck in V8). 78 // 79 // One could make the browser SIGKILL the renderers, but that leaves open a 80 // large window where a browser failure (or a user, manually terminating 81 // the browser because "it's stuck") will leave behind a process eating all 82 // the CPU. 83 // 84 // So, we install a filter on the channel so that we can process this event 85 // here and kill the process. 86 if (CommandLine::ForCurrentProcess()-> 87 HasSwitch(switches::kChildCleanExit)) { 88 // If clean exit is requested, we want to kill this process after giving 89 // it 60 seconds to run exit handlers. Exit handlers may including ones 90 // that write profile data to disk (which happens under profile collection 91 // mode). 92 alarm(60); 93#if defined(LEAK_SANITIZER) 94 // Invoke LeakSanitizer early to avoid detecting shutdown-only leaks. If 95 // leaks are found, the process will exit here. 96 __lsan_do_leak_check(); 97#endif 98 } else { 99 _exit(0); 100 } 101 } 102 103 protected: 104 virtual ~SuicideOnChannelErrorFilter() {} 105}; 106 107#endif // OS(POSIX) 108 109#if defined(OS_ANDROID) 110ChildThread* g_child_thread = NULL; 111 112// A lock protects g_child_thread. 113base::LazyInstance<base::Lock> g_lazy_child_thread_lock = 114 LAZY_INSTANCE_INITIALIZER; 115 116// base::ConditionVariable has an explicit constructor that takes 117// a base::Lock pointer as parameter. The base::DefaultLazyInstanceTraits 118// doesn't handle the case. Thus, we need our own class here. 119struct CondVarLazyInstanceTraits { 120 static const bool kRegisterOnExit = true; 121 static const bool kAllowedToAccessOnNonjoinableThread ALLOW_UNUSED = false; 122 static base::ConditionVariable* New(void* instance) { 123 return new (instance) base::ConditionVariable( 124 g_lazy_child_thread_lock.Pointer()); 125 } 126 static void Delete(base::ConditionVariable* instance) { 127 instance->~ConditionVariable(); 128 } 129}; 130 131// A condition variable that synchronize threads initializing and waiting 132// for g_child_thread. 133base::LazyInstance<base::ConditionVariable, CondVarLazyInstanceTraits> 134 g_lazy_child_thread_cv = LAZY_INSTANCE_INITIALIZER; 135 136void QuitMainThreadMessageLoop() { 137 base::MessageLoop::current()->Quit(); 138} 139 140#endif 141 142} // namespace 143 144ChildThread::ChildThread() 145 : channel_connected_factory_(this), 146 in_browser_process_(false) { 147 channel_name_ = CommandLine::ForCurrentProcess()->GetSwitchValueASCII( 148 switches::kProcessChannelID); 149 Init(); 150} 151 152ChildThread::ChildThread(const std::string& channel_name) 153 : channel_name_(channel_name), 154 channel_connected_factory_(this), 155 in_browser_process_(true) { 156 Init(); 157} 158 159void ChildThread::Init() { 160 g_lazy_tls.Pointer()->Set(this); 161 on_channel_error_called_ = false; 162 message_loop_ = base::MessageLoop::current(); 163#ifdef IPC_MESSAGE_LOG_ENABLED 164 // We must make sure to instantiate the IPC Logger *before* we create the 165 // channel, otherwise we can get a callback on the IO thread which creates 166 // the logger, and the logger does not like being created on the IO thread. 167 IPC::Logging::GetInstance(); 168#endif 169 channel_.reset( 170 new IPC::SyncChannel(channel_name_, 171 IPC::Channel::MODE_CLIENT, 172 this, 173 ChildProcess::current()->io_message_loop_proxy(), 174 true, 175 ChildProcess::current()->GetShutDownEvent())); 176#ifdef IPC_MESSAGE_LOG_ENABLED 177 if (!in_browser_process_) 178 IPC::Logging::GetInstance()->SetIPCSender(this); 179#endif 180 181 sync_message_filter_ = 182 new IPC::SyncMessageFilter(ChildProcess::current()->GetShutDownEvent()); 183 thread_safe_sender_ = new ThreadSafeSender( 184 base::MessageLoopProxy::current().get(), sync_message_filter_.get()); 185 186 resource_dispatcher_.reset(new ResourceDispatcher(this)); 187 socket_stream_dispatcher_.reset(new SocketStreamDispatcher()); 188 websocket_dispatcher_.reset(new WebSocketDispatcher); 189 file_system_dispatcher_.reset(new FileSystemDispatcher()); 190 191 histogram_message_filter_ = new ChildHistogramMessageFilter(); 192 resource_message_filter_ = 193 new ChildResourceMessageFilter(resource_dispatcher()); 194 195 service_worker_message_filter_ = 196 new ServiceWorkerMessageFilter(thread_safe_sender_.get()); 197 service_worker_dispatcher_.reset( 198 new ServiceWorkerDispatcher(thread_safe_sender_.get())); 199 200 quota_message_filter_ = 201 new QuotaMessageFilter(thread_safe_sender_.get()); 202 quota_dispatcher_.reset(new QuotaDispatcher(thread_safe_sender_.get(), 203 quota_message_filter_.get())); 204 205 channel_->AddFilter(histogram_message_filter_.get()); 206 channel_->AddFilter(sync_message_filter_.get()); 207 channel_->AddFilter(new tracing::ChildTraceMessageFilter( 208 ChildProcess::current()->io_message_loop_proxy())); 209 channel_->AddFilter(resource_message_filter_.get()); 210 channel_->AddFilter(quota_message_filter_->GetFilter()); 211 channel_->AddFilter(service_worker_message_filter_->GetFilter()); 212 213 // In single process mode we may already have a power monitor 214 if (!base::PowerMonitor::Get()) { 215 scoped_ptr<PowerMonitorBroadcastSource> power_monitor_source( 216 new PowerMonitorBroadcastSource()); 217 channel_->AddFilter(power_monitor_source->GetMessageFilter()); 218 219 power_monitor_.reset(new base::PowerMonitor( 220 power_monitor_source.PassAs<base::PowerMonitorSource>())); 221 } 222 223#if defined(OS_POSIX) 224 // Check that --process-type is specified so we don't do this in unit tests 225 // and single-process mode. 226 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kProcessType)) 227 channel_->AddFilter(new SuicideOnChannelErrorFilter()); 228#endif 229 230 base::MessageLoop::current()->PostDelayedTask( 231 FROM_HERE, 232 base::Bind(&ChildThread::EnsureConnected, 233 channel_connected_factory_.GetWeakPtr()), 234 base::TimeDelta::FromSeconds(kConnectionTimeoutS)); 235 236#if defined(OS_ANDROID) 237 { 238 base::AutoLock lock(g_lazy_child_thread_lock.Get()); 239 g_child_thread = this; 240 } 241 // Signalling without locking is fine here because only 242 // one thread can wait on the condition variable. 243 g_lazy_child_thread_cv.Get().Signal(); 244#endif 245 246#if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED) 247 trace_memory_controller_.reset(new base::debug::TraceMemoryController( 248 message_loop_->message_loop_proxy(), 249 ::HeapProfilerWithPseudoStackStart, 250 ::HeapProfilerStop, 251 ::GetHeapProfile)); 252#endif 253} 254 255ChildThread::~ChildThread() { 256#ifdef IPC_MESSAGE_LOG_ENABLED 257 IPC::Logging::GetInstance()->SetIPCSender(NULL); 258#endif 259 260 channel_->RemoveFilter(histogram_message_filter_.get()); 261 channel_->RemoveFilter(sync_message_filter_.get()); 262 263 // The ChannelProxy object caches a pointer to the IPC thread, so need to 264 // reset it as it's not guaranteed to outlive this object. 265 // NOTE: this also has the side-effect of not closing the main IPC channel to 266 // the browser process. This is needed because this is the signal that the 267 // browser uses to know that this process has died, so we need it to be alive 268 // until this process is shut down, and the OS closes the handle 269 // automatically. We used to watch the object handle on Windows to do this, 270 // but it wasn't possible to do so on POSIX. 271 channel_->ClearIPCTaskRunner(); 272 g_lazy_tls.Pointer()->Set(NULL); 273} 274 275void ChildThread::Shutdown() { 276 // Delete objects that hold references to blink so derived classes can 277 // safely shutdown blink in their Shutdown implementation. 278 file_system_dispatcher_.reset(); 279 quota_dispatcher_.reset(); 280} 281 282void ChildThread::OnChannelConnected(int32 peer_pid) { 283 channel_connected_factory_.InvalidateWeakPtrs(); 284} 285 286void ChildThread::OnChannelError() { 287 set_on_channel_error_called(true); 288 base::MessageLoop::current()->Quit(); 289} 290 291bool ChildThread::Send(IPC::Message* msg) { 292 DCHECK(base::MessageLoop::current() == message_loop()); 293 if (!channel_) { 294 delete msg; 295 return false; 296 } 297 298 return channel_->Send(msg); 299} 300 301void ChildThread::AddRoute(int32 routing_id, IPC::Listener* listener) { 302 DCHECK(base::MessageLoop::current() == message_loop()); 303 304 router_.AddRoute(routing_id, listener); 305} 306 307void ChildThread::RemoveRoute(int32 routing_id) { 308 DCHECK(base::MessageLoop::current() == message_loop()); 309 310 router_.RemoveRoute(routing_id); 311} 312 313webkit_glue::ResourceLoaderBridge* ChildThread::CreateBridge( 314 const webkit_glue::ResourceLoaderBridge::RequestInfo& request_info) { 315 return resource_dispatcher()->CreateBridge(request_info); 316} 317 318base::SharedMemory* ChildThread::AllocateSharedMemory(size_t buf_size) { 319 return AllocateSharedMemory(buf_size, this); 320} 321 322// static 323base::SharedMemory* ChildThread::AllocateSharedMemory( 324 size_t buf_size, 325 IPC::Sender* sender) { 326 scoped_ptr<base::SharedMemory> shared_buf; 327#if defined(OS_WIN) 328 shared_buf.reset(new base::SharedMemory); 329 if (!shared_buf->CreateAndMapAnonymous(buf_size)) { 330 NOTREACHED(); 331 return NULL; 332 } 333#else 334 // On POSIX, we need to ask the browser to create the shared memory for us, 335 // since this is blocked by the sandbox. 336 base::SharedMemoryHandle shared_mem_handle; 337 if (sender->Send(new ChildProcessHostMsg_SyncAllocateSharedMemory( 338 buf_size, &shared_mem_handle))) { 339 if (base::SharedMemory::IsHandleValid(shared_mem_handle)) { 340 shared_buf.reset(new base::SharedMemory(shared_mem_handle, false)); 341 if (!shared_buf->Map(buf_size)) { 342 NOTREACHED() << "Map failed"; 343 return NULL; 344 } 345 } else { 346 NOTREACHED() << "Browser failed to allocate shared memory"; 347 return NULL; 348 } 349 } else { 350 NOTREACHED() << "Browser allocation request message failed"; 351 return NULL; 352 } 353#endif 354 return shared_buf.release(); 355} 356 357bool ChildThread::OnMessageReceived(const IPC::Message& msg) { 358 // Resource responses are sent to the resource dispatcher. 359 if (resource_dispatcher_->OnMessageReceived(msg)) 360 return true; 361 if (socket_stream_dispatcher_->OnMessageReceived(msg)) 362 return true; 363 if (websocket_dispatcher_->OnMessageReceived(msg)) 364 return true; 365 if (file_system_dispatcher_->OnMessageReceived(msg)) 366 return true; 367 368 bool handled = true; 369 IPC_BEGIN_MESSAGE_MAP(ChildThread, msg) 370 IPC_MESSAGE_HANDLER(ChildProcessMsg_Shutdown, OnShutdown) 371#if defined(IPC_MESSAGE_LOG_ENABLED) 372 IPC_MESSAGE_HANDLER(ChildProcessMsg_SetIPCLoggingEnabled, 373 OnSetIPCLoggingEnabled) 374#endif 375 IPC_MESSAGE_HANDLER(ChildProcessMsg_SetProfilerStatus, 376 OnSetProfilerStatus) 377 IPC_MESSAGE_HANDLER(ChildProcessMsg_GetChildProfilerData, 378 OnGetChildProfilerData) 379 IPC_MESSAGE_HANDLER(ChildProcessMsg_DumpHandles, OnDumpHandles) 380#if defined(USE_TCMALLOC) 381 IPC_MESSAGE_HANDLER(ChildProcessMsg_GetTcmallocStats, OnGetTcmallocStats) 382#endif 383 IPC_MESSAGE_UNHANDLED(handled = false) 384 IPC_END_MESSAGE_MAP() 385 386 if (handled) 387 return true; 388 389 if (msg.routing_id() == MSG_ROUTING_CONTROL) 390 return OnControlMessageReceived(msg); 391 392 return router_.OnMessageReceived(msg); 393} 394 395bool ChildThread::OnControlMessageReceived(const IPC::Message& msg) { 396 return false; 397} 398 399void ChildThread::OnShutdown() { 400 base::MessageLoop::current()->Quit(); 401} 402 403#if defined(IPC_MESSAGE_LOG_ENABLED) 404void ChildThread::OnSetIPCLoggingEnabled(bool enable) { 405 if (enable) 406 IPC::Logging::GetInstance()->Enable(); 407 else 408 IPC::Logging::GetInstance()->Disable(); 409} 410#endif // IPC_MESSAGE_LOG_ENABLED 411 412void ChildThread::OnSetProfilerStatus(ThreadData::Status status) { 413 ThreadData::InitializeAndSetTrackingStatus(status); 414} 415 416void ChildThread::OnGetChildProfilerData(int sequence_number) { 417 tracked_objects::ProcessDataSnapshot process_data; 418 ThreadData::Snapshot(false, &process_data); 419 420 Send(new ChildProcessHostMsg_ChildProfilerData(sequence_number, 421 process_data)); 422} 423 424void ChildThread::OnDumpHandles() { 425#if defined(OS_WIN) 426 scoped_refptr<HandleEnumerator> handle_enum( 427 new HandleEnumerator( 428 CommandLine::ForCurrentProcess()->HasSwitch( 429 switches::kAuditAllHandles))); 430 handle_enum->EnumerateHandles(); 431 Send(new ChildProcessHostMsg_DumpHandlesDone); 432 return; 433#endif 434 435 NOTIMPLEMENTED(); 436} 437 438#if defined(USE_TCMALLOC) 439void ChildThread::OnGetTcmallocStats() { 440 std::string result; 441 char buffer[1024 * 32]; 442 base::allocator::GetStats(buffer, sizeof(buffer)); 443 result.append(buffer); 444 Send(new ChildProcessHostMsg_TcmallocStats(result)); 445} 446#endif 447 448ChildThread* ChildThread::current() { 449 return g_lazy_tls.Pointer()->Get(); 450} 451 452#if defined(OS_ANDROID) 453// The method must NOT be called on the child thread itself. 454// It may block the child thread if so. 455void ChildThread::ShutdownThread() { 456 DCHECK(!ChildThread::current()) << 457 "this method should NOT be called from child thread itself"; 458 { 459 base::AutoLock lock(g_lazy_child_thread_lock.Get()); 460 while (!g_child_thread) 461 g_lazy_child_thread_cv.Get().Wait(); 462 } 463 DCHECK_NE(base::MessageLoop::current(), g_child_thread->message_loop()); 464 g_child_thread->message_loop()->PostTask( 465 FROM_HERE, base::Bind(&QuitMainThreadMessageLoop)); 466} 467 468#endif 469 470void ChildThread::OnProcessFinalRelease() { 471 if (on_channel_error_called_) { 472 base::MessageLoop::current()->Quit(); 473 return; 474 } 475 476 // The child process shutdown sequence is a request response based mechanism, 477 // where we send out an initial feeler request to the child process host 478 // instance in the browser to verify if it's ok to shutdown the child process. 479 // The browser then sends back a response if it's ok to shutdown. This avoids 480 // race conditions if the process refcount is 0 but there's an IPC message 481 // inflight that would addref it. 482 Send(new ChildProcessHostMsg_ShutdownRequest); 483} 484 485void ChildThread::EnsureConnected() { 486 VLOG(0) << "ChildThread::EnsureConnected()"; 487 base::KillProcess(base::GetCurrentProcessHandle(), 0, false); 488} 489 490} // namespace content 491