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