| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/child/child_thread_impl.h" | 5 #include "content/child/child_thread_impl.h" |
| 6 | 6 |
| 7 #include <signal.h> | 7 #include <signal.h> |
| 8 | 8 |
| 9 #include <string> | 9 #include <string> |
| 10 | 10 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 52 #include "content/child/websocket_dispatcher.h" | 52 #include "content/child/websocket_dispatcher.h" |
| 53 #include "content/common/child_process_messages.h" | 53 #include "content/common/child_process_messages.h" |
| 54 #include "content/common/in_process_child_thread_params.h" | 54 #include "content/common/in_process_child_thread_params.h" |
| 55 #include "content/public/common/content_switches.h" | 55 #include "content/public/common/content_switches.h" |
| 56 #include "ipc/ipc_logging.h" | 56 #include "ipc/ipc_logging.h" |
| 57 #include "ipc/ipc_switches.h" | 57 #include "ipc/ipc_switches.h" |
| 58 #include "ipc/ipc_sync_channel.h" | 58 #include "ipc/ipc_sync_channel.h" |
| 59 #include "ipc/ipc_sync_message_filter.h" | 59 #include "ipc/ipc_sync_message_filter.h" |
| 60 #include "ipc/mojo/ipc_channel_mojo.h" | 60 #include "ipc/mojo/ipc_channel_mojo.h" |
| 61 | 61 |
| 62 #if defined(OS_ANDROID) |
| 63 #include "base/thread_task_runner_handle.h" |
| 64 #endif |
| 65 |
| 62 #if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED) | 66 #if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED) |
| 63 #include "third_party/tcmalloc/chromium/src/gperftools/heap-profiler.h" | 67 #include "third_party/tcmalloc/chromium/src/gperftools/heap-profiler.h" |
| 64 #endif | 68 #endif |
| 65 | 69 |
| 66 using tracked_objects::ThreadData; | 70 using tracked_objects::ThreadData; |
| 67 | 71 |
| 68 namespace content { | 72 namespace content { |
| 69 namespace { | 73 namespace { |
| 70 | 74 |
| 71 // How long to wait for a connection to the browser process before giving up. | 75 // How long to wait for a connection to the browser process before giving up. |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 154 #endif | 158 #endif |
| 155 } | 159 } |
| 156 | 160 |
| 157 protected: | 161 protected: |
| 158 ~SuicideOnChannelErrorFilter() override {} | 162 ~SuicideOnChannelErrorFilter() override {} |
| 159 }; | 163 }; |
| 160 | 164 |
| 161 #endif // OS(POSIX) | 165 #endif // OS(POSIX) |
| 162 | 166 |
| 163 #if defined(OS_ANDROID) | 167 #if defined(OS_ANDROID) |
| 164 ChildThreadImpl* g_child_thread = NULL; | 168 // A class that allows for triggering a clean shutdown from another |
| 165 bool g_child_thread_initialized = false; | 169 // thread through draining the main thread's msg loop. |
| 170 class QuitClosure { |
| 171 public: |
| 172 QuitClosure(); |
| 173 ~QuitClosure(); |
| 166 | 174 |
| 167 // A lock protects g_child_thread. | 175 void BindToMainThread(); |
| 168 base::LazyInstance<base::Lock>::Leaky g_lazy_child_thread_lock = | 176 void PostQuitFromNonMainThread(); |
| 169 LAZY_INSTANCE_INITIALIZER; | |
| 170 | 177 |
| 171 // base::ConditionVariable has an explicit constructor that takes | 178 private: |
| 172 // a base::Lock pointer as parameter. The base::DefaultLazyInstanceTraits | 179 static void PostClosure( |
| 173 // doesn't handle the case. Thus, we need our own class here. | 180 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, |
| 174 struct CondVarLazyInstanceTraits { | 181 base::Closure closure); |
| 175 static const bool kRegisterOnExit = false; | |
| 176 #ifndef NDEBUG | |
| 177 static const bool kAllowedToAccessOnNonjoinableThread = true; | |
| 178 #endif | |
| 179 | 182 |
| 180 static base::ConditionVariable* New(void* instance) { | 183 base::Lock lock_; |
| 181 return new (instance) base::ConditionVariable( | 184 base::ConditionVariable cond_var_; |
| 182 g_lazy_child_thread_lock.Pointer()); | 185 base::Closure closure_; |
| 183 } | |
| 184 static void Delete(base::ConditionVariable* instance) { | |
| 185 instance->~ConditionVariable(); | |
| 186 } | |
| 187 }; | 186 }; |
| 188 | 187 |
| 189 // A condition variable that synchronize threads initializing and waiting | 188 QuitClosure::QuitClosure() : cond_var_(&lock_) { |
| 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 } | 189 } |
| 197 | 190 |
| 191 QuitClosure::~QuitClosure() { |
| 192 } |
| 193 |
| 194 void QuitClosure::PostClosure( |
| 195 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, |
| 196 base::Closure closure) { |
| 197 task_runner->PostTask(FROM_HERE, closure); |
| 198 } |
| 199 |
| 200 void QuitClosure::BindToMainThread() { |
| 201 base::AutoLock lock(lock_); |
| 202 scoped_refptr<base::SingleThreadTaskRunner> task_runner( |
| 203 base::ThreadTaskRunnerHandle::Get()); |
| 204 base::Closure quit_closure = |
| 205 base::MessageLoop::current()->QuitWhenIdleClosure(); |
| 206 closure_ = base::Bind(&QuitClosure::PostClosure, task_runner, quit_closure); |
| 207 cond_var_.Signal(); |
| 208 } |
| 209 |
| 210 void QuitClosure::PostQuitFromNonMainThread() { |
| 211 base::AutoLock lock(lock_); |
| 212 while (closure_.is_null()) |
| 213 cond_var_.Wait(); |
| 214 |
| 215 closure_.Run(); |
| 216 } |
| 217 |
| 218 base::LazyInstance<QuitClosure> g_quit_closure = LAZY_INSTANCE_INITIALIZER; |
| 198 #endif | 219 #endif |
| 199 | 220 |
| 200 } // namespace | 221 } // namespace |
| 201 | 222 |
| 202 ChildThread* ChildThread::Get() { | 223 ChildThread* ChildThread::Get() { |
| 203 return ChildThreadImpl::current(); | 224 return ChildThreadImpl::current(); |
| 204 } | 225 } |
| 205 | 226 |
| 206 ChildThreadImpl::Options::Options() | 227 ChildThreadImpl::Options::Options() |
| 207 : channel_name(base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( | 228 : channel_name(base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 395 connection_timeout = temp; | 416 connection_timeout = temp; |
| 396 } | 417 } |
| 397 | 418 |
| 398 base::MessageLoop::current()->PostDelayedTask( | 419 base::MessageLoop::current()->PostDelayedTask( |
| 399 FROM_HERE, | 420 FROM_HERE, |
| 400 base::Bind(&ChildThreadImpl::EnsureConnected, | 421 base::Bind(&ChildThreadImpl::EnsureConnected, |
| 401 channel_connected_factory_.GetWeakPtr()), | 422 channel_connected_factory_.GetWeakPtr()), |
| 402 base::TimeDelta::FromSeconds(connection_timeout)); | 423 base::TimeDelta::FromSeconds(connection_timeout)); |
| 403 | 424 |
| 404 #if defined(OS_ANDROID) | 425 #if defined(OS_ANDROID) |
| 405 { | 426 g_quit_closure.Get().BindToMainThread(); |
| 406 base::AutoLock lock(g_lazy_child_thread_lock.Get()); | |
| 407 g_child_thread = this; | |
| 408 g_child_thread_initialized = true; | |
| 409 } | |
| 410 // Signalling without locking is fine here because only | |
| 411 // one thread can wait on the condition variable. | |
| 412 g_lazy_child_thread_cv.Get().Signal(); | |
| 413 #endif | 427 #endif |
| 414 | 428 |
| 415 #if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED) | 429 #if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED) |
| 416 trace_memory_controller_.reset(new base::trace_event::TraceMemoryController( | 430 trace_memory_controller_.reset(new base::trace_event::TraceMemoryController( |
| 417 message_loop_->message_loop_proxy(), ::HeapProfilerWithPseudoStackStart, | 431 message_loop_->message_loop_proxy(), ::HeapProfilerWithPseudoStackStart, |
| 418 ::HeapProfilerStop, ::GetHeapProfile)); | 432 ::HeapProfilerStop, ::GetHeapProfile)); |
| 419 #endif | 433 #endif |
| 420 | 434 |
| 421 base::trace_event::MemoryDumpManager::GetInstance()->Initialize(); | 435 base::trace_event::MemoryDumpManager::GetInstance()->Initialize(); |
| 422 | 436 |
| 423 shared_bitmap_manager_.reset( | 437 shared_bitmap_manager_.reset( |
| 424 new ChildSharedBitmapManager(thread_safe_sender())); | 438 new ChildSharedBitmapManager(thread_safe_sender())); |
| 425 | 439 |
| 426 gpu_memory_buffer_manager_.reset( | 440 gpu_memory_buffer_manager_.reset( |
| 427 new ChildGpuMemoryBufferManager(thread_safe_sender())); | 441 new ChildGpuMemoryBufferManager(thread_safe_sender())); |
| 428 | 442 |
| 429 discardable_shared_memory_manager_.reset( | 443 discardable_shared_memory_manager_.reset( |
| 430 new ChildDiscardableSharedMemoryManager(thread_safe_sender())); | 444 new ChildDiscardableSharedMemoryManager(thread_safe_sender())); |
| 431 } | 445 } |
| 432 | 446 |
| 433 ChildThreadImpl::~ChildThreadImpl() { | 447 ChildThreadImpl::~ChildThreadImpl() { |
| 434 // ChildDiscardableSharedMemoryManager has to be destroyed while | 448 // ChildDiscardableSharedMemoryManager has to be destroyed while |
| 435 // |thread_safe_sender_| is still valid. | 449 // |thread_safe_sender_| is still valid. |
| 436 discardable_shared_memory_manager_.reset(); | 450 discardable_shared_memory_manager_.reset(); |
| 437 | 451 |
| 438 #if defined(OS_ANDROID) | |
| 439 { | |
| 440 base::AutoLock lock(g_lazy_child_thread_lock.Get()); | |
| 441 g_child_thread = nullptr; | |
| 442 } | |
| 443 #endif | |
| 444 | |
| 445 #ifdef IPC_MESSAGE_LOG_ENABLED | 452 #ifdef IPC_MESSAGE_LOG_ENABLED |
| 446 IPC::Logging::GetInstance()->SetIPCSender(NULL); | 453 IPC::Logging::GetInstance()->SetIPCSender(NULL); |
| 447 #endif | 454 #endif |
| 448 | 455 |
| 449 channel_->RemoveFilter(histogram_message_filter_.get()); | 456 channel_->RemoveFilter(histogram_message_filter_.get()); |
| 450 channel_->RemoveFilter(sync_message_filter_.get()); | 457 channel_->RemoveFilter(sync_message_filter_.get()); |
| 451 | 458 |
| 452 // The ChannelProxy object caches a pointer to the IPC thread, so need to | 459 // The ChannelProxy object caches a pointer to the IPC thread, so need to |
| 453 // reset it as it's not guaranteed to outlive this object. | 460 // reset it as it's not guaranteed to outlive this object. |
| 454 // NOTE: this also has the side-effect of not closing the main IPC channel to | 461 // NOTE: this also has the side-effect of not closing the main IPC channel to |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 629 ChildThreadImpl* ChildThreadImpl::current() { | 636 ChildThreadImpl* ChildThreadImpl::current() { |
| 630 return g_lazy_tls.Pointer()->Get(); | 637 return g_lazy_tls.Pointer()->Get(); |
| 631 } | 638 } |
| 632 | 639 |
| 633 #if defined(OS_ANDROID) | 640 #if defined(OS_ANDROID) |
| 634 // The method must NOT be called on the child thread itself. | 641 // The method must NOT be called on the child thread itself. |
| 635 // It may block the child thread if so. | 642 // It may block the child thread if so. |
| 636 void ChildThreadImpl::ShutdownThread() { | 643 void ChildThreadImpl::ShutdownThread() { |
| 637 DCHECK(!ChildThreadImpl::current()) << | 644 DCHECK(!ChildThreadImpl::current()) << |
| 638 "this method should NOT be called from child thread itself"; | 645 "this method should NOT be called from child thread itself"; |
| 639 { | 646 g_quit_closure.Get().PostQuitFromNonMainThread(); |
| 640 base::AutoLock lock(g_lazy_child_thread_lock.Get()); | |
| 641 while (!g_child_thread_initialized) | |
| 642 g_lazy_child_thread_cv.Get().Wait(); | |
| 643 | |
| 644 // g_child_thread may already have been destructed while we didn't hold the | |
| 645 // lock. | |
| 646 if (!g_child_thread) | |
| 647 return; | |
| 648 | |
| 649 DCHECK_NE(base::MessageLoop::current(), g_child_thread->message_loop()); | |
| 650 g_child_thread->message_loop()->PostTask( | |
| 651 FROM_HERE, base::Bind(&QuitMainThreadMessageLoop)); | |
| 652 } | |
| 653 } | 647 } |
| 654 #endif | 648 #endif |
| 655 | 649 |
| 656 void ChildThreadImpl::OnProcessFinalRelease() { | 650 void ChildThreadImpl::OnProcessFinalRelease() { |
| 657 if (on_channel_error_called_) { | 651 if (on_channel_error_called_) { |
| 658 base::MessageLoop::current()->Quit(); | 652 base::MessageLoop::current()->Quit(); |
| 659 return; | 653 return; |
| 660 } | 654 } |
| 661 | 655 |
| 662 // The child process shutdown sequence is a request response based mechanism, | 656 // The child process shutdown sequence is a request response based mechanism, |
| (...skipping 16 matching lines...) Expand all Loading... |
| 679 | 673 |
| 680 void ChildThreadImpl::OnProcessBackgrounded(bool background) { | 674 void ChildThreadImpl::OnProcessBackgrounded(bool background) { |
| 681 // Set timer slack to maximum on main thread when in background. | 675 // Set timer slack to maximum on main thread when in background. |
| 682 base::TimerSlack timer_slack = base::TIMER_SLACK_NONE; | 676 base::TimerSlack timer_slack = base::TIMER_SLACK_NONE; |
| 683 if (background) | 677 if (background) |
| 684 timer_slack = base::TIMER_SLACK_MAXIMUM; | 678 timer_slack = base::TIMER_SLACK_MAXIMUM; |
| 685 base::MessageLoop::current()->SetTimerSlack(timer_slack); | 679 base::MessageLoop::current()->SetTimerSlack(timer_slack); |
| 686 } | 680 } |
| 687 | 681 |
| 688 } // namespace content | 682 } // namespace content |
| OLD | NEW |