| OLD | NEW |
| (Empty) |
| 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 <signal.h> | |
| 8 | |
| 9 #include <string> | |
| 10 | |
| 11 #include "base/allocator/allocator_extension.h" | |
| 12 #include "base/base_switches.h" | |
| 13 #include "base/basictypes.h" | |
| 14 #include "base/command_line.h" | |
| 15 #include "base/debug/leak_annotations.h" | |
| 16 #include "base/lazy_instance.h" | |
| 17 #include "base/logging.h" | |
| 18 #include "base/message_loop/message_loop.h" | |
| 19 #include "base/message_loop/timer_slack.h" | |
| 20 #include "base/process/kill.h" | |
| 21 #include "base/process/process_handle.h" | |
| 22 #include "base/strings/string_number_conversions.h" | |
| 23 #include "base/strings/string_util.h" | |
| 24 #include "base/synchronization/condition_variable.h" | |
| 25 #include "base/synchronization/lock.h" | |
| 26 #include "base/threading/thread_local.h" | |
| 27 #include "base/tracked_objects.h" | |
| 28 #include "components/tracing/child_trace_message_filter.h" | |
| 29 #include "content/child/bluetooth/bluetooth_message_filter.h" | |
| 30 #include "content/child/child_discardable_shared_memory_manager.h" | |
| 31 #include "content/child/child_gpu_memory_buffer_manager.h" | |
| 32 #include "content/child/child_histogram_message_filter.h" | |
| 33 #include "content/child/child_process.h" | |
| 34 #include "content/child/child_resource_message_filter.h" | |
| 35 #include "content/child/child_shared_bitmap_manager.h" | |
| 36 #include "content/child/fileapi/file_system_dispatcher.h" | |
| 37 #include "content/child/fileapi/webfilesystem_impl.h" | |
| 38 #include "content/child/geofencing/geofencing_message_filter.h" | |
| 39 #include "content/child/mojo/mojo_application.h" | |
| 40 #include "content/child/navigator_connect/navigator_connect_dispatcher.h" | |
| 41 #include "content/child/notifications/notification_dispatcher.h" | |
| 42 #include "content/child/power_monitor_broadcast_source.h" | |
| 43 #include "content/child/push_messaging/push_dispatcher.h" | |
| 44 #include "content/child/quota_dispatcher.h" | |
| 45 #include "content/child/quota_message_filter.h" | |
| 46 #include "content/child/resource_dispatcher.h" | |
| 47 #include "content/child/service_worker/service_worker_message_filter.h" | |
| 48 #include "content/child/thread_safe_sender.h" | |
| 49 #include "content/child/websocket_dispatcher.h" | |
| 50 #include "content/common/child_process_messages.h" | |
| 51 #include "content/public/common/content_switches.h" | |
| 52 #include "ipc/ipc_logging.h" | |
| 53 #include "ipc/ipc_switches.h" | |
| 54 #include "ipc/ipc_sync_channel.h" | |
| 55 #include "ipc/ipc_sync_message_filter.h" | |
| 56 #include "ipc/mojo/ipc_channel_mojo.h" | |
| 57 | |
| 58 #if defined(OS_WIN) | |
| 59 #include "content/common/handle_enumerator_win.h" | |
| 60 #endif | |
| 61 | |
| 62 #if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED) | |
| 63 #include "third_party/tcmalloc/chromium/src/gperftools/heap-profiler.h" | |
| 64 #endif | |
| 65 | |
| 66 using tracked_objects::ThreadData; | |
| 67 | |
| 68 namespace content { | |
| 69 namespace { | |
| 70 | |
| 71 // How long to wait for a connection to the browser process before giving up. | |
| 72 const int kConnectionTimeoutS = 15; | |
| 73 | |
| 74 base::LazyInstance<base::ThreadLocalPointer<ChildThread> > g_lazy_tls = | |
| 75 LAZY_INSTANCE_INITIALIZER; | |
| 76 | |
| 77 // This isn't needed on Windows because there the sandbox's job object | |
| 78 // terminates child processes automatically. For unsandboxed processes (i.e. | |
| 79 // plugins), PluginThread has EnsureTerminateMessageFilter. | |
| 80 #if defined(OS_POSIX) | |
| 81 | |
| 82 // TODO(earthdok): Re-enable on CrOS http://crbug.com/360622 | |
| 83 #if (defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || \ | |
| 84 defined(MEMORY_SANITIZER) || defined(THREAD_SANITIZER) || \ | |
| 85 defined(UNDEFINED_SANITIZER)) && !defined(OS_CHROMEOS) | |
| 86 // A thread delegate that waits for |duration| and then exits the process with | |
| 87 // _exit(0). | |
| 88 class WaitAndExitDelegate : public base::PlatformThread::Delegate { | |
| 89 public: | |
| 90 explicit WaitAndExitDelegate(base::TimeDelta duration) | |
| 91 : duration_(duration) {} | |
| 92 | |
| 93 void ThreadMain() override { | |
| 94 base::PlatformThread::Sleep(duration_); | |
| 95 _exit(0); | |
| 96 } | |
| 97 | |
| 98 private: | |
| 99 const base::TimeDelta duration_; | |
| 100 DISALLOW_COPY_AND_ASSIGN(WaitAndExitDelegate); | |
| 101 }; | |
| 102 | |
| 103 bool CreateWaitAndExitThread(base::TimeDelta duration) { | |
| 104 scoped_ptr<WaitAndExitDelegate> delegate(new WaitAndExitDelegate(duration)); | |
| 105 | |
| 106 const bool thread_created = | |
| 107 base::PlatformThread::CreateNonJoinable(0, delegate.get()); | |
| 108 if (!thread_created) | |
| 109 return false; | |
| 110 | |
| 111 // A non joinable thread has been created. The thread will either terminate | |
| 112 // the process or will be terminated by the process. Therefore, keep the | |
| 113 // delegate object alive for the lifetime of the process. | |
| 114 WaitAndExitDelegate* leaking_delegate = delegate.release(); | |
| 115 ANNOTATE_LEAKING_OBJECT_PTR(leaking_delegate); | |
| 116 ignore_result(leaking_delegate); | |
| 117 return true; | |
| 118 } | |
| 119 #endif | |
| 120 | |
| 121 class SuicideOnChannelErrorFilter : public IPC::MessageFilter { | |
| 122 public: | |
| 123 // IPC::MessageFilter | |
| 124 void OnChannelError() override { | |
| 125 // For renderer/worker processes: | |
| 126 // On POSIX, at least, one can install an unload handler which loops | |
| 127 // forever and leave behind a renderer process which eats 100% CPU forever. | |
| 128 // | |
| 129 // This is because the terminate signals (ViewMsg_ShouldClose and the error | |
| 130 // from the IPC sender) are routed to the main message loop but never | |
| 131 // processed (because that message loop is stuck in V8). | |
| 132 // | |
| 133 // One could make the browser SIGKILL the renderers, but that leaves open a | |
| 134 // large window where a browser failure (or a user, manually terminating | |
| 135 // the browser because "it's stuck") will leave behind a process eating all | |
| 136 // the CPU. | |
| 137 // | |
| 138 // So, we install a filter on the sender so that we can process this event | |
| 139 // here and kill the process. | |
| 140 // TODO(earthdok): Re-enable on CrOS http://crbug.com/360622 | |
| 141 #if (defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || \ | |
| 142 defined(MEMORY_SANITIZER) || defined(THREAD_SANITIZER) || \ | |
| 143 defined(UNDEFINED_SANITIZER)) && !defined(OS_CHROMEOS) | |
| 144 // Some sanitizer tools rely on exit handlers (e.g. to run leak detection, | |
| 145 // or dump code coverage data to disk). Instead of exiting the process | |
| 146 // immediately, we give it 60 seconds to run exit handlers. | |
| 147 CHECK(CreateWaitAndExitThread(base::TimeDelta::FromSeconds(60))); | |
| 148 #if defined(LEAK_SANITIZER) | |
| 149 // Invoke LeakSanitizer early to avoid detecting shutdown-only leaks. If | |
| 150 // leaks are found, the process will exit here. | |
| 151 __lsan_do_leak_check(); | |
| 152 #endif | |
| 153 #else | |
| 154 _exit(0); | |
| 155 #endif | |
| 156 } | |
| 157 | |
| 158 protected: | |
| 159 ~SuicideOnChannelErrorFilter() override {} | |
| 160 }; | |
| 161 | |
| 162 #endif // OS(POSIX) | |
| 163 | |
| 164 #if defined(OS_ANDROID) | |
| 165 ChildThread* g_child_thread = NULL; | |
| 166 | |
| 167 // A lock protects g_child_thread. | |
| 168 base::LazyInstance<base::Lock> g_lazy_child_thread_lock = | |
| 169 LAZY_INSTANCE_INITIALIZER; | |
| 170 | |
| 171 // base::ConditionVariable has an explicit constructor that takes | |
| 172 // a base::Lock pointer as parameter. The base::DefaultLazyInstanceTraits | |
| 173 // doesn't handle the case. Thus, we need our own class here. | |
| 174 struct CondVarLazyInstanceTraits { | |
| 175 static const bool kRegisterOnExit = true; | |
| 176 #ifndef NDEBUG | |
| 177 static const bool kAllowedToAccessOnNonjoinableThread = false; | |
| 178 #endif | |
| 179 | |
| 180 static base::ConditionVariable* New(void* instance) { | |
| 181 return new (instance) base::ConditionVariable( | |
| 182 g_lazy_child_thread_lock.Pointer()); | |
| 183 } | |
| 184 static void Delete(base::ConditionVariable* instance) { | |
| 185 instance->~ConditionVariable(); | |
| 186 } | |
| 187 }; | |
| 188 | |
| 189 // A condition variable that synchronize threads initializing and waiting | |
| 190 // for g_child_thread. | |
| 191 base::LazyInstance<base::ConditionVariable, CondVarLazyInstanceTraits> | |
| 192 g_lazy_child_thread_cv = LAZY_INSTANCE_INITIALIZER; | |
| 193 | |
| 194 void QuitMainThreadMessageLoop() { | |
| 195 base::MessageLoop::current()->Quit(); | |
| 196 } | |
| 197 | |
| 198 #endif | |
| 199 | |
| 200 } // namespace | |
| 201 | |
| 202 ChildThread::Options::Options() | |
| 203 : channel_name(base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( | |
| 204 switches::kProcessChannelID)), | |
| 205 use_mojo_channel(false), | |
| 206 in_browser_process(false) { | |
| 207 } | |
| 208 | |
| 209 ChildThread::Options::Options(bool mojo) | |
| 210 : channel_name(base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( | |
| 211 switches::kProcessChannelID)), | |
| 212 use_mojo_channel(mojo), | |
| 213 in_browser_process(true) { | |
| 214 } | |
| 215 | |
| 216 ChildThread::Options::Options(std::string name, bool mojo) | |
| 217 : channel_name(name), use_mojo_channel(mojo), in_browser_process(true) { | |
| 218 } | |
| 219 | |
| 220 ChildThread::Options::~Options() { | |
| 221 } | |
| 222 | |
| 223 ChildThread::ChildThreadMessageRouter::ChildThreadMessageRouter( | |
| 224 IPC::Sender* sender) | |
| 225 : sender_(sender) {} | |
| 226 | |
| 227 bool ChildThread::ChildThreadMessageRouter::Send(IPC::Message* msg) { | |
| 228 return sender_->Send(msg); | |
| 229 } | |
| 230 | |
| 231 ChildThread::ChildThread() | |
| 232 : router_(this), | |
| 233 in_browser_process_(false), | |
| 234 channel_connected_factory_(this) { | |
| 235 Init(Options()); | |
| 236 } | |
| 237 | |
| 238 ChildThread::ChildThread(const Options& options) | |
| 239 : router_(this), | |
| 240 in_browser_process_(options.in_browser_process), | |
| 241 channel_connected_factory_(this) { | |
| 242 Init(options); | |
| 243 } | |
| 244 | |
| 245 void ChildThread::ConnectChannel(bool use_mojo_channel) { | |
| 246 bool create_pipe_now = true; | |
| 247 if (use_mojo_channel) { | |
| 248 VLOG(1) << "Mojo is enabled on child"; | |
| 249 channel_->Init(IPC::ChannelMojo::CreateClientFactory(channel_name_), | |
| 250 create_pipe_now); | |
| 251 return; | |
| 252 } | |
| 253 | |
| 254 VLOG(1) << "Mojo is disabled on child"; | |
| 255 channel_->Init(channel_name_, IPC::Channel::MODE_CLIENT, create_pipe_now); | |
| 256 } | |
| 257 | |
| 258 void ChildThread::Init(const Options& options) { | |
| 259 channel_name_ = options.channel_name; | |
| 260 | |
| 261 g_lazy_tls.Pointer()->Set(this); | |
| 262 on_channel_error_called_ = false; | |
| 263 message_loop_ = base::MessageLoop::current(); | |
| 264 #ifdef IPC_MESSAGE_LOG_ENABLED | |
| 265 // We must make sure to instantiate the IPC Logger *before* we create the | |
| 266 // channel, otherwise we can get a callback on the IO thread which creates | |
| 267 // the logger, and the logger does not like being created on the IO thread. | |
| 268 IPC::Logging::GetInstance(); | |
| 269 #endif | |
| 270 channel_ = IPC::SyncChannel::Create( | |
| 271 this, ChildProcess::current()->io_message_loop_proxy(), | |
| 272 ChildProcess::current()->GetShutDownEvent()); | |
| 273 #ifdef IPC_MESSAGE_LOG_ENABLED | |
| 274 if (!in_browser_process_) | |
| 275 IPC::Logging::GetInstance()->SetIPCSender(this); | |
| 276 #endif | |
| 277 | |
| 278 mojo_application_.reset(new MojoApplication); | |
| 279 | |
| 280 sync_message_filter_ = | |
| 281 new IPC::SyncMessageFilter(ChildProcess::current()->GetShutDownEvent()); | |
| 282 thread_safe_sender_ = new ThreadSafeSender( | |
| 283 base::MessageLoopProxy::current().get(), sync_message_filter_.get()); | |
| 284 | |
| 285 resource_dispatcher_.reset(new ResourceDispatcher( | |
| 286 this, message_loop()->task_runner())); | |
| 287 websocket_dispatcher_.reset(new WebSocketDispatcher); | |
| 288 file_system_dispatcher_.reset(new FileSystemDispatcher()); | |
| 289 | |
| 290 histogram_message_filter_ = new ChildHistogramMessageFilter(); | |
| 291 resource_message_filter_ = | |
| 292 new ChildResourceMessageFilter(resource_dispatcher()); | |
| 293 | |
| 294 service_worker_message_filter_ = | |
| 295 new ServiceWorkerMessageFilter(thread_safe_sender_.get()); | |
| 296 | |
| 297 quota_message_filter_ = | |
| 298 new QuotaMessageFilter(thread_safe_sender_.get()); | |
| 299 quota_dispatcher_.reset(new QuotaDispatcher(thread_safe_sender_.get(), | |
| 300 quota_message_filter_.get())); | |
| 301 geofencing_message_filter_ = | |
| 302 new GeofencingMessageFilter(thread_safe_sender_.get()); | |
| 303 bluetooth_message_filter_ = | |
| 304 new BluetoothMessageFilter(thread_safe_sender_.get()); | |
| 305 notification_dispatcher_ = | |
| 306 new NotificationDispatcher(thread_safe_sender_.get()); | |
| 307 push_dispatcher_ = new PushDispatcher(thread_safe_sender_.get()); | |
| 308 navigator_connect_dispatcher_ = | |
| 309 new NavigatorConnectDispatcher(thread_safe_sender_.get()); | |
| 310 | |
| 311 channel_->AddFilter(histogram_message_filter_.get()); | |
| 312 channel_->AddFilter(sync_message_filter_.get()); | |
| 313 channel_->AddFilter(resource_message_filter_.get()); | |
| 314 channel_->AddFilter(quota_message_filter_->GetFilter()); | |
| 315 channel_->AddFilter(notification_dispatcher_->GetFilter()); | |
| 316 channel_->AddFilter(push_dispatcher_->GetFilter()); | |
| 317 channel_->AddFilter(service_worker_message_filter_->GetFilter()); | |
| 318 channel_->AddFilter(geofencing_message_filter_->GetFilter()); | |
| 319 channel_->AddFilter(bluetooth_message_filter_->GetFilter()); | |
| 320 channel_->AddFilter(navigator_connect_dispatcher_->GetFilter()); | |
| 321 | |
| 322 if (!base::CommandLine::ForCurrentProcess()->HasSwitch( | |
| 323 switches::kSingleProcess)) { | |
| 324 // In single process mode, browser-side tracing will cover the whole | |
| 325 // process including renderers. | |
| 326 channel_->AddFilter(new tracing::ChildTraceMessageFilter( | |
| 327 ChildProcess::current()->io_message_loop_proxy())); | |
| 328 } | |
| 329 | |
| 330 // In single process mode we may already have a power monitor | |
| 331 if (!base::PowerMonitor::Get()) { | |
| 332 scoped_ptr<PowerMonitorBroadcastSource> power_monitor_source( | |
| 333 new PowerMonitorBroadcastSource()); | |
| 334 channel_->AddFilter(power_monitor_source->GetMessageFilter()); | |
| 335 | |
| 336 power_monitor_.reset(new base::PowerMonitor( | |
| 337 power_monitor_source.Pass())); | |
| 338 } | |
| 339 | |
| 340 #if defined(OS_POSIX) | |
| 341 // Check that --process-type is specified so we don't do this in unit tests | |
| 342 // and single-process mode. | |
| 343 if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kProcessType)) | |
| 344 channel_->AddFilter(new SuicideOnChannelErrorFilter()); | |
| 345 #endif | |
| 346 | |
| 347 // Add filters passed here via options. | |
| 348 for (auto startup_filter : options.startup_filters) { | |
| 349 channel_->AddFilter(startup_filter); | |
| 350 } | |
| 351 | |
| 352 ConnectChannel(options.use_mojo_channel); | |
| 353 | |
| 354 int connection_timeout = kConnectionTimeoutS; | |
| 355 std::string connection_override = | |
| 356 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( | |
| 357 switches::kIPCConnectionTimeout); | |
| 358 if (!connection_override.empty()) { | |
| 359 int temp; | |
| 360 if (base::StringToInt(connection_override, &temp)) | |
| 361 connection_timeout = temp; | |
| 362 } | |
| 363 | |
| 364 base::MessageLoop::current()->PostDelayedTask( | |
| 365 FROM_HERE, | |
| 366 base::Bind(&ChildThread::EnsureConnected, | |
| 367 channel_connected_factory_.GetWeakPtr()), | |
| 368 base::TimeDelta::FromSeconds(connection_timeout)); | |
| 369 | |
| 370 #if defined(OS_ANDROID) | |
| 371 { | |
| 372 base::AutoLock lock(g_lazy_child_thread_lock.Get()); | |
| 373 g_child_thread = this; | |
| 374 } | |
| 375 // Signalling without locking is fine here because only | |
| 376 // one thread can wait on the condition variable. | |
| 377 g_lazy_child_thread_cv.Get().Signal(); | |
| 378 #endif | |
| 379 | |
| 380 #if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED) | |
| 381 trace_memory_controller_.reset(new base::debug::TraceMemoryController( | |
| 382 message_loop_->message_loop_proxy(), | |
| 383 ::HeapProfilerWithPseudoStackStart, | |
| 384 ::HeapProfilerStop, | |
| 385 ::GetHeapProfile)); | |
| 386 #endif | |
| 387 | |
| 388 shared_bitmap_manager_.reset( | |
| 389 new ChildSharedBitmapManager(thread_safe_sender())); | |
| 390 | |
| 391 gpu_memory_buffer_manager_.reset( | |
| 392 new ChildGpuMemoryBufferManager(thread_safe_sender())); | |
| 393 | |
| 394 discardable_shared_memory_manager_.reset( | |
| 395 new ChildDiscardableSharedMemoryManager(thread_safe_sender())); | |
| 396 } | |
| 397 | |
| 398 ChildThread::~ChildThread() { | |
| 399 #ifdef IPC_MESSAGE_LOG_ENABLED | |
| 400 IPC::Logging::GetInstance()->SetIPCSender(NULL); | |
| 401 #endif | |
| 402 | |
| 403 channel_->RemoveFilter(histogram_message_filter_.get()); | |
| 404 channel_->RemoveFilter(sync_message_filter_.get()); | |
| 405 | |
| 406 // The ChannelProxy object caches a pointer to the IPC thread, so need to | |
| 407 // reset it as it's not guaranteed to outlive this object. | |
| 408 // NOTE: this also has the side-effect of not closing the main IPC channel to | |
| 409 // the browser process. This is needed because this is the signal that the | |
| 410 // browser uses to know that this process has died, so we need it to be alive | |
| 411 // until this process is shut down, and the OS closes the handle | |
| 412 // automatically. We used to watch the object handle on Windows to do this, | |
| 413 // but it wasn't possible to do so on POSIX. | |
| 414 channel_->ClearIPCTaskRunner(); | |
| 415 g_lazy_tls.Pointer()->Set(NULL); | |
| 416 } | |
| 417 | |
| 418 void ChildThread::Shutdown() { | |
| 419 // Delete objects that hold references to blink so derived classes can | |
| 420 // safely shutdown blink in their Shutdown implementation. | |
| 421 file_system_dispatcher_.reset(); | |
| 422 quota_dispatcher_.reset(); | |
| 423 WebFileSystemImpl::DeleteThreadSpecificInstance(); | |
| 424 } | |
| 425 | |
| 426 void ChildThread::OnChannelConnected(int32 peer_pid) { | |
| 427 channel_connected_factory_.InvalidateWeakPtrs(); | |
| 428 } | |
| 429 | |
| 430 void ChildThread::OnChannelError() { | |
| 431 set_on_channel_error_called(true); | |
| 432 base::MessageLoop::current()->Quit(); | |
| 433 } | |
| 434 | |
| 435 bool ChildThread::Send(IPC::Message* msg) { | |
| 436 DCHECK(base::MessageLoop::current() == message_loop()); | |
| 437 if (!channel_) { | |
| 438 delete msg; | |
| 439 return false; | |
| 440 } | |
| 441 | |
| 442 return channel_->Send(msg); | |
| 443 } | |
| 444 | |
| 445 MessageRouter* ChildThread::GetRouter() { | |
| 446 DCHECK(base::MessageLoop::current() == message_loop()); | |
| 447 return &router_; | |
| 448 } | |
| 449 | |
| 450 scoped_ptr<base::SharedMemory> ChildThread::AllocateSharedMemory( | |
| 451 size_t buf_size) { | |
| 452 DCHECK(base::MessageLoop::current() == message_loop()); | |
| 453 return AllocateSharedMemory(buf_size, this); | |
| 454 } | |
| 455 | |
| 456 // static | |
| 457 scoped_ptr<base::SharedMemory> ChildThread::AllocateSharedMemory( | |
| 458 size_t buf_size, | |
| 459 IPC::Sender* sender) { | |
| 460 scoped_ptr<base::SharedMemory> shared_buf; | |
| 461 #if defined(OS_WIN) | |
| 462 shared_buf.reset(new base::SharedMemory); | |
| 463 if (!shared_buf->CreateAnonymous(buf_size)) { | |
| 464 NOTREACHED(); | |
| 465 return NULL; | |
| 466 } | |
| 467 #else | |
| 468 // On POSIX, we need to ask the browser to create the shared memory for us, | |
| 469 // since this is blocked by the sandbox. | |
| 470 base::SharedMemoryHandle shared_mem_handle; | |
| 471 if (sender->Send(new ChildProcessHostMsg_SyncAllocateSharedMemory( | |
| 472 buf_size, &shared_mem_handle))) { | |
| 473 if (base::SharedMemory::IsHandleValid(shared_mem_handle)) { | |
| 474 shared_buf.reset(new base::SharedMemory(shared_mem_handle, false)); | |
| 475 } else { | |
| 476 NOTREACHED() << "Browser failed to allocate shared memory"; | |
| 477 return NULL; | |
| 478 } | |
| 479 } else { | |
| 480 NOTREACHED() << "Browser allocation request message failed"; | |
| 481 return NULL; | |
| 482 } | |
| 483 #endif | |
| 484 return shared_buf; | |
| 485 } | |
| 486 | |
| 487 bool ChildThread::OnMessageReceived(const IPC::Message& msg) { | |
| 488 if (mojo_application_->OnMessageReceived(msg)) | |
| 489 return true; | |
| 490 | |
| 491 // Resource responses are sent to the resource dispatcher. | |
| 492 if (resource_dispatcher_->OnMessageReceived(msg)) | |
| 493 return true; | |
| 494 if (websocket_dispatcher_->OnMessageReceived(msg)) | |
| 495 return true; | |
| 496 if (file_system_dispatcher_->OnMessageReceived(msg)) | |
| 497 return true; | |
| 498 | |
| 499 bool handled = true; | |
| 500 IPC_BEGIN_MESSAGE_MAP(ChildThread, msg) | |
| 501 IPC_MESSAGE_HANDLER(ChildProcessMsg_Shutdown, OnShutdown) | |
| 502 #if defined(IPC_MESSAGE_LOG_ENABLED) | |
| 503 IPC_MESSAGE_HANDLER(ChildProcessMsg_SetIPCLoggingEnabled, | |
| 504 OnSetIPCLoggingEnabled) | |
| 505 #endif | |
| 506 IPC_MESSAGE_HANDLER(ChildProcessMsg_SetProfilerStatus, | |
| 507 OnSetProfilerStatus) | |
| 508 IPC_MESSAGE_HANDLER(ChildProcessMsg_GetChildProfilerData, | |
| 509 OnGetChildProfilerData) | |
| 510 IPC_MESSAGE_HANDLER(ChildProcessMsg_DumpHandles, OnDumpHandles) | |
| 511 IPC_MESSAGE_HANDLER(ChildProcessMsg_SetProcessBackgrounded, | |
| 512 OnProcessBackgrounded) | |
| 513 #if defined(USE_TCMALLOC) | |
| 514 IPC_MESSAGE_HANDLER(ChildProcessMsg_GetTcmallocStats, OnGetTcmallocStats) | |
| 515 #endif | |
| 516 IPC_MESSAGE_UNHANDLED(handled = false) | |
| 517 IPC_END_MESSAGE_MAP() | |
| 518 | |
| 519 if (handled) | |
| 520 return true; | |
| 521 | |
| 522 if (msg.routing_id() == MSG_ROUTING_CONTROL) | |
| 523 return OnControlMessageReceived(msg); | |
| 524 | |
| 525 return router_.OnMessageReceived(msg); | |
| 526 } | |
| 527 | |
| 528 bool ChildThread::OnControlMessageReceived(const IPC::Message& msg) { | |
| 529 return false; | |
| 530 } | |
| 531 | |
| 532 void ChildThread::OnShutdown() { | |
| 533 base::MessageLoop::current()->Quit(); | |
| 534 } | |
| 535 | |
| 536 #if defined(IPC_MESSAGE_LOG_ENABLED) | |
| 537 void ChildThread::OnSetIPCLoggingEnabled(bool enable) { | |
| 538 if (enable) | |
| 539 IPC::Logging::GetInstance()->Enable(); | |
| 540 else | |
| 541 IPC::Logging::GetInstance()->Disable(); | |
| 542 } | |
| 543 #endif // IPC_MESSAGE_LOG_ENABLED | |
| 544 | |
| 545 void ChildThread::OnSetProfilerStatus(ThreadData::Status status) { | |
| 546 ThreadData::InitializeAndSetTrackingStatus(status); | |
| 547 } | |
| 548 | |
| 549 void ChildThread::OnGetChildProfilerData(int sequence_number) { | |
| 550 tracked_objects::ProcessDataSnapshot process_data; | |
| 551 ThreadData::Snapshot(false, &process_data); | |
| 552 | |
| 553 Send(new ChildProcessHostMsg_ChildProfilerData(sequence_number, | |
| 554 process_data)); | |
| 555 } | |
| 556 | |
| 557 void ChildThread::OnDumpHandles() { | |
| 558 #if defined(OS_WIN) | |
| 559 scoped_refptr<HandleEnumerator> handle_enum( | |
| 560 new HandleEnumerator( | |
| 561 base::CommandLine::ForCurrentProcess()->HasSwitch( | |
| 562 switches::kAuditAllHandles))); | |
| 563 handle_enum->EnumerateHandles(); | |
| 564 Send(new ChildProcessHostMsg_DumpHandlesDone); | |
| 565 #else | |
| 566 NOTIMPLEMENTED(); | |
| 567 #endif | |
| 568 } | |
| 569 | |
| 570 #if defined(USE_TCMALLOC) | |
| 571 void ChildThread::OnGetTcmallocStats() { | |
| 572 std::string result; | |
| 573 char buffer[1024 * 32]; | |
| 574 base::allocator::GetStats(buffer, sizeof(buffer)); | |
| 575 result.append(buffer); | |
| 576 Send(new ChildProcessHostMsg_TcmallocStats(result)); | |
| 577 } | |
| 578 #endif | |
| 579 | |
| 580 ChildThread* ChildThread::current() { | |
| 581 return g_lazy_tls.Pointer()->Get(); | |
| 582 } | |
| 583 | |
| 584 #if defined(OS_ANDROID) | |
| 585 // The method must NOT be called on the child thread itself. | |
| 586 // It may block the child thread if so. | |
| 587 void ChildThread::ShutdownThread() { | |
| 588 DCHECK(!ChildThread::current()) << | |
| 589 "this method should NOT be called from child thread itself"; | |
| 590 { | |
| 591 base::AutoLock lock(g_lazy_child_thread_lock.Get()); | |
| 592 while (!g_child_thread) | |
| 593 g_lazy_child_thread_cv.Get().Wait(); | |
| 594 } | |
| 595 DCHECK_NE(base::MessageLoop::current(), g_child_thread->message_loop()); | |
| 596 g_child_thread->message_loop()->PostTask( | |
| 597 FROM_HERE, base::Bind(&QuitMainThreadMessageLoop)); | |
| 598 } | |
| 599 #endif | |
| 600 | |
| 601 void ChildThread::OnProcessFinalRelease() { | |
| 602 if (on_channel_error_called_) { | |
| 603 base::MessageLoop::current()->Quit(); | |
| 604 return; | |
| 605 } | |
| 606 | |
| 607 // The child process shutdown sequence is a request response based mechanism, | |
| 608 // where we send out an initial feeler request to the child process host | |
| 609 // instance in the browser to verify if it's ok to shutdown the child process. | |
| 610 // The browser then sends back a response if it's ok to shutdown. This avoids | |
| 611 // race conditions if the process refcount is 0 but there's an IPC message | |
| 612 // inflight that would addref it. | |
| 613 Send(new ChildProcessHostMsg_ShutdownRequest); | |
| 614 } | |
| 615 | |
| 616 void ChildThread::EnsureConnected() { | |
| 617 VLOG(0) << "ChildThread::EnsureConnected()"; | |
| 618 base::KillProcess(base::GetCurrentProcessHandle(), 0, false); | |
| 619 } | |
| 620 | |
| 621 void ChildThread::OnProcessBackgrounded(bool background) { | |
| 622 // Set timer slack to maximum on main thread when in background. | |
| 623 base::TimerSlack timer_slack = base::TIMER_SLACK_NONE; | |
| 624 if (background) | |
| 625 timer_slack = base::TIMER_SLACK_MAXIMUM; | |
| 626 base::MessageLoop::current()->SetTimerSlack(timer_slack); | |
| 627 } | |
| 628 | |
| 629 } // namespace content | |
| OLD | NEW |