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