• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/gpu/gpu_child_thread.h"
6 
7 #include "base/bind.h"
8 #include "base/lazy_instance.h"
9 #include "base/threading/worker_pool.h"
10 #include "build/build_config.h"
11 #include "content/child/child_process.h"
12 #include "content/child/thread_safe_sender.h"
13 #include "content/common/gpu/gpu_messages.h"
14 #include "content/gpu/gpu_watchdog_thread.h"
15 #include "content/public/common/content_client.h"
16 #include "content/public/common/content_switches.h"
17 #include "gpu/config/gpu_info_collector.h"
18 #include "ipc/ipc_channel_handle.h"
19 #include "ipc/ipc_sync_message_filter.h"
20 #include "ui/gl/gl_implementation.h"
21 
22 #if defined(USE_OZONE)
23 #include "ui/ozone/public/gpu_platform_support.h"
24 #include "ui/ozone/public/ozone_platform.h"
25 #endif
26 
27 namespace content {
28 namespace {
29 
30 static base::LazyInstance<scoped_refptr<ThreadSafeSender> >
31     g_thread_safe_sender = LAZY_INSTANCE_INITIALIZER;
32 
GpuProcessLogMessageHandler(int severity,const char * file,int line,size_t message_start,const std::string & str)33 bool GpuProcessLogMessageHandler(int severity,
34                                  const char* file, int line,
35                                  size_t message_start,
36                                  const std::string& str) {
37   std::string header = str.substr(0, message_start);
38   std::string message = str.substr(message_start);
39 
40   g_thread_safe_sender.Get()->Send(new GpuHostMsg_OnLogMessage(
41       severity, header, message));
42 
43   return false;
44 }
45 
46 }  // namespace
47 
GpuChildThread(GpuWatchdogThread * watchdog_thread,bool dead_on_arrival,const gpu::GPUInfo & gpu_info,const DeferredMessages & deferred_messages)48 GpuChildThread::GpuChildThread(GpuWatchdogThread* watchdog_thread,
49                                bool dead_on_arrival,
50                                const gpu::GPUInfo& gpu_info,
51                                const DeferredMessages& deferred_messages)
52     : dead_on_arrival_(dead_on_arrival),
53       gpu_info_(gpu_info),
54       deferred_messages_(deferred_messages),
55       in_browser_process_(false) {
56   watchdog_thread_ = watchdog_thread;
57 #if defined(OS_WIN)
58   target_services_ = NULL;
59 #endif
60   g_thread_safe_sender.Get() = thread_safe_sender();
61 }
62 
GpuChildThread(const std::string & channel_id)63 GpuChildThread::GpuChildThread(const std::string& channel_id)
64     : ChildThread(Options(channel_id, false)),
65       dead_on_arrival_(false),
66       in_browser_process_(true) {
67 #if defined(OS_WIN)
68   target_services_ = NULL;
69 #endif
70   DCHECK(
71       CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess) ||
72       CommandLine::ForCurrentProcess()->HasSwitch(switches::kInProcessGPU));
73 #if !defined(OS_ANDROID)
74   // For single process and in-process GPU mode, we need to load and
75   // initialize the GL implementation and locate the GL entry points here.
76   // On Android, GLSurface::InitializeOneOff() is called from BrowserMainLoop
77   // before getting here. crbug.com/326295
78   if (!gfx::GLSurface::InitializeOneOff())
79     VLOG(1) << "gfx::GLSurface::InitializeOneOff failed";
80 #endif
81   g_thread_safe_sender.Get() = thread_safe_sender();
82 }
83 
~GpuChildThread()84 GpuChildThread::~GpuChildThread() {
85 }
86 
Shutdown()87 void GpuChildThread::Shutdown() {
88   ChildThread::Shutdown();
89   logging::SetLogMessageHandler(NULL);
90 }
91 
Init(const base::Time & process_start_time)92 void GpuChildThread::Init(const base::Time& process_start_time) {
93   process_start_time_ = process_start_time;
94 }
95 
Send(IPC::Message * msg)96 bool GpuChildThread::Send(IPC::Message* msg) {
97   // The GPU process must never send a synchronous IPC message to the browser
98   // process. This could result in deadlock.
99   DCHECK(!msg->is_sync());
100 
101   return ChildThread::Send(msg);
102 }
103 
OnControlMessageReceived(const IPC::Message & msg)104 bool GpuChildThread::OnControlMessageReceived(const IPC::Message& msg) {
105   bool handled = true;
106   IPC_BEGIN_MESSAGE_MAP(GpuChildThread, msg)
107     IPC_MESSAGE_HANDLER(GpuMsg_Initialize, OnInitialize)
108     IPC_MESSAGE_HANDLER(GpuMsg_CollectGraphicsInfo, OnCollectGraphicsInfo)
109     IPC_MESSAGE_HANDLER(GpuMsg_GetVideoMemoryUsageStats,
110                         OnGetVideoMemoryUsageStats)
111     IPC_MESSAGE_HANDLER(GpuMsg_Clean, OnClean)
112     IPC_MESSAGE_HANDLER(GpuMsg_Crash, OnCrash)
113     IPC_MESSAGE_HANDLER(GpuMsg_Hang, OnHang)
114     IPC_MESSAGE_HANDLER(GpuMsg_DisableWatchdog, OnDisableWatchdog)
115     IPC_MESSAGE_UNHANDLED(handled = false)
116   IPC_END_MESSAGE_MAP()
117 
118   if (handled)
119     return true;
120 
121 #if defined(USE_OZONE)
122   if (ui::OzonePlatform::GetInstance()
123           ->GetGpuPlatformSupport()
124           ->OnMessageReceived(msg))
125     return true;
126 #endif
127 
128   return gpu_channel_manager_.get() &&
129       gpu_channel_manager_->OnMessageReceived(msg);
130 }
131 
OnInitialize()132 void GpuChildThread::OnInitialize() {
133   // Record initialization only after collecting the GPU info because that can
134   // take a significant amount of time.
135   gpu_info_.initialization_time = base::Time::Now() - process_start_time_;
136   Send(new GpuHostMsg_Initialized(!dead_on_arrival_, gpu_info_));
137   while (!deferred_messages_.empty()) {
138     Send(deferred_messages_.front());
139     deferred_messages_.pop();
140   }
141 
142   if (dead_on_arrival_) {
143     LOG(ERROR) << "Exiting GPU process due to errors during initialization";
144     base::MessageLoop::current()->Quit();
145     return;
146   }
147 
148 #if defined(OS_ANDROID)
149   base::PlatformThread::SetThreadPriority(
150       base::PlatformThread::CurrentHandle(),
151       base::kThreadPriority_Display);
152 #endif
153 
154   // We don't need to pipe log messages if we are running the GPU thread in
155   // the browser process.
156   if (!in_browser_process_)
157     logging::SetLogMessageHandler(GpuProcessLogMessageHandler);
158 
159   // Defer creation of the render thread. This is to prevent it from handling
160   // IPC messages before the sandbox has been enabled and all other necessary
161   // initialization has succeeded.
162   gpu_channel_manager_.reset(
163       new GpuChannelManager(GetRouter(),
164                             watchdog_thread_.get(),
165                             ChildProcess::current()->io_message_loop_proxy(),
166                             ChildProcess::current()->GetShutDownEvent(),
167                             channel()));
168 
169 #if defined(USE_OZONE)
170   ui::OzonePlatform::GetInstance()
171       ->GetGpuPlatformSupport()
172       ->OnChannelEstablished(this);
173 #endif
174 }
175 
StopWatchdog()176 void GpuChildThread::StopWatchdog() {
177   if (watchdog_thread_.get()) {
178     watchdog_thread_->Stop();
179   }
180 }
181 
OnCollectGraphicsInfo()182 void GpuChildThread::OnCollectGraphicsInfo() {
183 #if defined(OS_WIN)
184   // GPU full info collection should only happen on un-sandboxed GPU process
185   // or single process/in-process gpu mode on Windows.
186   CommandLine* command_line = CommandLine::ForCurrentProcess();
187   DCHECK(command_line->HasSwitch(switches::kDisableGpuSandbox) ||
188          in_browser_process_);
189 #endif  // OS_WIN
190 
191   gpu::CollectInfoResult result =
192       gpu::CollectContextGraphicsInfo(&gpu_info_);
193   switch (result) {
194     case gpu::kCollectInfoFatalFailure:
195       LOG(ERROR) << "gpu::CollectGraphicsInfo failed (fatal).";
196       // TODO(piman): can we signal overall failure?
197       break;
198     case gpu::kCollectInfoNonFatalFailure:
199       VLOG(1) << "gpu::CollectGraphicsInfo failed (non-fatal).";
200       break;
201     case gpu::kCollectInfoNone:
202       NOTREACHED();
203       break;
204     case gpu::kCollectInfoSuccess:
205       break;
206   }
207   GetContentClient()->SetGpuInfo(gpu_info_);
208 
209 #if defined(OS_WIN)
210   // This is slow, but it's the only thing the unsandboxed GPU process does,
211   // and GpuDataManager prevents us from sending multiple collecting requests,
212   // so it's OK to be blocking.
213   gpu::GetDxDiagnostics(&gpu_info_.dx_diagnostics);
214   gpu_info_.dx_diagnostics_info_state = gpu::kCollectInfoSuccess;
215 #endif  // OS_WIN
216 
217   Send(new GpuHostMsg_GraphicsInfoCollected(gpu_info_));
218 
219 #if defined(OS_WIN)
220   if (!in_browser_process_) {
221     // The unsandboxed GPU process fulfilled its duty.  Rest in peace.
222     base::MessageLoop::current()->Quit();
223   }
224 #endif  // OS_WIN
225 }
226 
OnGetVideoMemoryUsageStats()227 void GpuChildThread::OnGetVideoMemoryUsageStats() {
228   GPUVideoMemoryUsageStats video_memory_usage_stats;
229   if (gpu_channel_manager_)
230     gpu_channel_manager_->gpu_memory_manager()->GetVideoMemoryUsageStats(
231         &video_memory_usage_stats);
232   Send(new GpuHostMsg_VideoMemoryUsageStats(video_memory_usage_stats));
233 }
234 
OnClean()235 void GpuChildThread::OnClean() {
236   VLOG(1) << "GPU: Removing all contexts";
237   if (gpu_channel_manager_)
238     gpu_channel_manager_->LoseAllContexts();
239 }
240 
OnCrash()241 void GpuChildThread::OnCrash() {
242   VLOG(1) << "GPU: Simulating GPU crash";
243   // Good bye, cruel world.
244   volatile int* it_s_the_end_of_the_world_as_we_know_it = NULL;
245   *it_s_the_end_of_the_world_as_we_know_it = 0xdead;
246 }
247 
OnHang()248 void GpuChildThread::OnHang() {
249   VLOG(1) << "GPU: Simulating GPU hang";
250   for (;;) {
251     // Do not sleep here. The GPU watchdog timer tracks the amount of user
252     // time this thread is using and it doesn't use much while calling Sleep.
253   }
254 }
255 
OnDisableWatchdog()256 void GpuChildThread::OnDisableWatchdog() {
257   VLOG(1) << "GPU: Disabling watchdog thread";
258   if (watchdog_thread_.get()) {
259     // Disarm the watchdog before shutting down the message loop. This prevents
260     // the future posting of tasks to the message loop.
261     if (watchdog_thread_->message_loop())
262       watchdog_thread_->PostAcknowledge();
263     // Prevent rearming.
264     watchdog_thread_->Stop();
265   }
266 }
267 
268 }  // namespace content
269 
270