Supervised user whitelists: Cleanup
[chromium-blink-merge.git] / content / browser / gpu / gpu_internals_ui.cc
blob6a4985f7324f484a45eb430f8dfc31fec4443493
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.
5 #include "content/browser/gpu/gpu_internals_ui.h"
7 #if defined(OS_LINUX) && defined(USE_X11)
8 #include <X11/Xlib.h>
9 #endif
11 #include <string>
13 #include "base/bind.h"
14 #include "base/bind_helpers.h"
15 #include "base/command_line.h"
16 #include "base/environment.h"
17 #include "base/i18n/time_formatting.h"
18 #include "base/strings/string_number_conversions.h"
19 #include "base/strings/stringprintf.h"
20 #include "base/sys_info.h"
21 #include "base/values.h"
22 #include "content/browser/gpu/compositor_util.h"
23 #include "content/browser/gpu/gpu_data_manager_impl.h"
24 #include "content/grit/content_resources.h"
25 #include "content/public/browser/browser_thread.h"
26 #include "content/public/browser/gpu_data_manager_observer.h"
27 #include "content/public/browser/web_contents.h"
28 #include "content/public/browser/web_ui.h"
29 #include "content/public/browser/web_ui_data_source.h"
30 #include "content/public/browser/web_ui_message_handler.h"
31 #include "content/public/common/content_client.h"
32 #include "content/public/common/content_switches.h"
33 #include "content/public/common/url_constants.h"
34 #include "gpu/config/gpu_feature_type.h"
35 #include "gpu/config/gpu_info.h"
36 #include "third_party/angle/src/common/version.h"
37 #include "ui/gl/gpu_switching_manager.h"
39 #if defined(OS_WIN)
40 #include "ui/base/win/shell.h"
41 #endif
43 #if defined(OS_LINUX) && defined(USE_X11)
44 #include "ui/base/x/x11_util.h"
45 #include "ui/gfx/x/x11_atom_cache.h"
46 #endif
48 namespace content {
49 namespace {
51 WebUIDataSource* CreateGpuHTMLSource() {
52 WebUIDataSource* source = WebUIDataSource::Create(kChromeUIGpuHost);
54 source->SetJsonPath("strings.js");
55 source->AddResourcePath("gpu_internals.js", IDR_GPU_INTERNALS_JS);
56 source->SetDefaultResource(IDR_GPU_INTERNALS_HTML);
57 return source;
60 base::DictionaryValue* NewDescriptionValuePair(const std::string& desc,
61 const std::string& value) {
62 base::DictionaryValue* dict = new base::DictionaryValue();
63 dict->SetString("description", desc);
64 dict->SetString("value", value);
65 return dict;
68 base::DictionaryValue* NewDescriptionValuePair(const std::string& desc,
69 base::Value* value) {
70 base::DictionaryValue* dict = new base::DictionaryValue();
71 dict->SetString("description", desc);
72 dict->Set("value", value);
73 return dict;
76 #if defined(OS_WIN)
77 // Output DxDiagNode tree as nested array of {description,value} pairs
78 base::ListValue* DxDiagNodeToList(const gpu::DxDiagNode& node) {
79 base::ListValue* list = new base::ListValue();
80 for (std::map<std::string, std::string>::const_iterator it =
81 node.values.begin();
82 it != node.values.end();
83 ++it) {
84 list->Append(NewDescriptionValuePair(it->first, it->second));
87 for (std::map<std::string, gpu::DxDiagNode>::const_iterator it =
88 node.children.begin();
89 it != node.children.end();
90 ++it) {
91 base::ListValue* sublist = DxDiagNodeToList(it->second);
92 list->Append(NewDescriptionValuePair(it->first, sublist));
94 return list;
96 #endif
98 std::string GPUDeviceToString(const gpu::GPUInfo::GPUDevice& gpu) {
99 std::string vendor = base::StringPrintf("0x%04x", gpu.vendor_id);
100 if (!gpu.vendor_string.empty())
101 vendor += " [" + gpu.vendor_string + "]";
102 std::string device = base::StringPrintf("0x%04x", gpu.device_id);
103 if (!gpu.device_string.empty())
104 device += " [" + gpu.device_string + "]";
105 return base::StringPrintf("VENDOR = %s, DEVICE= %s%s",
106 vendor.c_str(), device.c_str(), gpu.active ? " *ACTIVE*" : "");
109 base::DictionaryValue* GpuInfoAsDictionaryValue() {
110 gpu::GPUInfo gpu_info = GpuDataManagerImpl::GetInstance()->GetGPUInfo();
111 base::ListValue* basic_info = new base::ListValue();
112 basic_info->Append(NewDescriptionValuePair(
113 "Initialization time",
114 base::Int64ToString(gpu_info.initialization_time.InMilliseconds())));
115 basic_info->Append(NewDescriptionValuePair(
116 "Sandboxed", new base::FundamentalValue(gpu_info.sandboxed)));
117 basic_info->Append(NewDescriptionValuePair(
118 "GPU0", GPUDeviceToString(gpu_info.gpu)));
119 for (size_t i = 0; i < gpu_info.secondary_gpus.size(); ++i) {
120 basic_info->Append(NewDescriptionValuePair(
121 base::StringPrintf("GPU%d", static_cast<int>(i + 1)),
122 GPUDeviceToString(gpu_info.secondary_gpus[i])));
124 basic_info->Append(NewDescriptionValuePair(
125 "Optimus", new base::FundamentalValue(gpu_info.optimus)));
126 basic_info->Append(NewDescriptionValuePair(
127 "AMD switchable", new base::FundamentalValue(gpu_info.amd_switchable)));
128 if (gpu_info.lenovo_dcute) {
129 basic_info->Append(NewDescriptionValuePair(
130 "Lenovo dCute", new base::FundamentalValue(true)));
132 if (gpu_info.display_link_version.IsValid()) {
133 basic_info->Append(NewDescriptionValuePair(
134 "DisplayLink Version", gpu_info.display_link_version.GetString()));
136 #if defined(OS_WIN)
137 std::string compositor =
138 ui::win::IsAeroGlassEnabled() ? "Aero Glass" : "none";
139 basic_info->Append(
140 NewDescriptionValuePair("Desktop compositing", compositor));
141 if (GpuDataManagerImpl::GetInstance()->ShouldUseWarp()) {
142 basic_info->Append(NewDescriptionValuePair("Using WARP",
143 new base::FundamentalValue(true)));
145 #endif
147 basic_info->Append(
148 NewDescriptionValuePair("Driver vendor", gpu_info.driver_vendor));
149 basic_info->Append(NewDescriptionValuePair("Driver version",
150 gpu_info.driver_version));
151 basic_info->Append(NewDescriptionValuePair("Driver date",
152 gpu_info.driver_date));
153 basic_info->Append(NewDescriptionValuePair("Pixel shader version",
154 gpu_info.pixel_shader_version));
155 basic_info->Append(NewDescriptionValuePair("Vertex shader version",
156 gpu_info.vertex_shader_version));
157 basic_info->Append(NewDescriptionValuePair("Max. MSAA samples",
158 gpu_info.max_msaa_samples));
159 basic_info->Append(NewDescriptionValuePair("Machine model name",
160 gpu_info.machine_model_name));
161 basic_info->Append(NewDescriptionValuePair("Machine model version",
162 gpu_info.machine_model_version));
163 basic_info->Append(NewDescriptionValuePair("GL_VENDOR",
164 gpu_info.gl_vendor));
165 basic_info->Append(NewDescriptionValuePair("GL_RENDERER",
166 gpu_info.gl_renderer));
167 basic_info->Append(NewDescriptionValuePair("GL_VERSION",
168 gpu_info.gl_version));
169 basic_info->Append(NewDescriptionValuePair("GL_EXTENSIONS",
170 gpu_info.gl_extensions));
171 basic_info->Append(NewDescriptionValuePair("Window system binding vendor",
172 gpu_info.gl_ws_vendor));
173 basic_info->Append(NewDescriptionValuePair("Window system binding version",
174 gpu_info.gl_ws_version));
175 basic_info->Append(NewDescriptionValuePair("Window system binding extensions",
176 gpu_info.gl_ws_extensions));
177 #if defined(OS_LINUX) && defined(USE_X11)
178 basic_info->Append(NewDescriptionValuePair("Window manager",
179 ui::GuessWindowManagerName()));
181 scoped_ptr<base::Environment> env(base::Environment::Create());
182 std::string value;
183 const char kXDGCurrentDesktop[] = "XDG_CURRENT_DESKTOP";
184 if (env->GetVar(kXDGCurrentDesktop, &value))
185 basic_info->Append(NewDescriptionValuePair(kXDGCurrentDesktop, value));
186 const char kGDMSession[] = "GDMSESSION";
187 if (env->GetVar(kGDMSession, &value))
188 basic_info->Append(NewDescriptionValuePair(kGDMSession, value));
189 const char* kAtomsToCache[] = {
190 "_NET_WM_CM_S0",
191 NULL
193 ui::X11AtomCache atom_cache(gfx::GetXDisplay(), kAtomsToCache);
194 std::string compositing_manager = XGetSelectionOwner(
195 gfx::GetXDisplay(),
196 atom_cache.GetAtom("_NET_WM_CM_S0")) != None ? "Yes" : "No";
197 basic_info->Append(
198 NewDescriptionValuePair("Compositing manager", compositing_manager));
200 #endif
201 std::string direct_rendering = gpu_info.direct_rendering ? "Yes" : "No";
202 basic_info->Append(
203 NewDescriptionValuePair("Direct rendering", direct_rendering));
205 std::string reset_strategy =
206 base::StringPrintf("0x%04x", gpu_info.gl_reset_notification_strategy);
207 basic_info->Append(NewDescriptionValuePair(
208 "Reset notification strategy", reset_strategy));
210 basic_info->Append(NewDescriptionValuePair(
211 "GPU process crash count",
212 new base::FundamentalValue(gpu_info.process_crash_count)));
214 base::DictionaryValue* info = new base::DictionaryValue();
215 info->Set("basic_info", basic_info);
217 #if defined(OS_WIN)
218 base::Value* dx_info = gpu_info.dx_diagnostics.children.size() ?
219 DxDiagNodeToList(gpu_info.dx_diagnostics) :
220 base::Value::CreateNullValue();
221 info->Set("diagnostics", dx_info);
222 #endif
224 return info;
227 // This class receives javascript messages from the renderer.
228 // Note that the WebUI infrastructure runs on the UI thread, therefore all of
229 // this class's methods are expected to run on the UI thread.
230 class GpuMessageHandler
231 : public WebUIMessageHandler,
232 public base::SupportsWeakPtr<GpuMessageHandler>,
233 public GpuDataManagerObserver,
234 public ui::GpuSwitchingObserver {
235 public:
236 GpuMessageHandler();
237 ~GpuMessageHandler() override;
239 // WebUIMessageHandler implementation.
240 void RegisterMessages() override;
242 // GpuDataManagerObserver implementation.
243 void OnGpuInfoUpdate() override;
245 // ui::GpuSwitchingObserver implementation.
246 void OnGpuSwitched() override;
248 // Messages
249 void OnBrowserBridgeInitialized(const base::ListValue* list);
250 void OnCallAsync(const base::ListValue* list);
252 // Submessages dispatched from OnCallAsync
253 base::Value* OnRequestClientInfo(const base::ListValue* list);
254 base::Value* OnRequestLogMessages(const base::ListValue* list);
256 private:
257 // True if observing the GpuDataManager (re-attaching as observer would
258 // DCHECK).
259 bool observing_;
261 DISALLOW_COPY_AND_ASSIGN(GpuMessageHandler);
264 ////////////////////////////////////////////////////////////////////////////////
266 // GpuMessageHandler
268 ////////////////////////////////////////////////////////////////////////////////
270 GpuMessageHandler::GpuMessageHandler()
271 : observing_(false) {
274 GpuMessageHandler::~GpuMessageHandler() {
275 ui::GpuSwitchingManager::GetInstance()->RemoveObserver(this);
276 GpuDataManagerImpl::GetInstance()->RemoveObserver(this);
279 /* BrowserBridge.callAsync prepends a requestID to these messages. */
280 void GpuMessageHandler::RegisterMessages() {
281 DCHECK_CURRENTLY_ON(BrowserThread::UI);
283 web_ui()->RegisterMessageCallback("browserBridgeInitialized",
284 base::Bind(&GpuMessageHandler::OnBrowserBridgeInitialized,
285 base::Unretained(this)));
286 web_ui()->RegisterMessageCallback("callAsync",
287 base::Bind(&GpuMessageHandler::OnCallAsync,
288 base::Unretained(this)));
291 void GpuMessageHandler::OnCallAsync(const base::ListValue* args) {
292 DCHECK_GE(args->GetSize(), static_cast<size_t>(2));
293 // unpack args into requestId, submessage and submessageArgs
294 bool ok;
295 const base::Value* requestId;
296 ok = args->Get(0, &requestId);
297 DCHECK(ok);
299 std::string submessage;
300 ok = args->GetString(1, &submessage);
301 DCHECK(ok);
303 base::ListValue* submessageArgs = new base::ListValue();
304 for (size_t i = 2; i < args->GetSize(); ++i) {
305 const base::Value* arg;
306 ok = args->Get(i, &arg);
307 DCHECK(ok);
309 base::Value* argCopy = arg->DeepCopy();
310 submessageArgs->Append(argCopy);
313 // call the submessage handler
314 base::Value* ret = NULL;
315 if (submessage == "requestClientInfo") {
316 ret = OnRequestClientInfo(submessageArgs);
317 } else if (submessage == "requestLogMessages") {
318 ret = OnRequestLogMessages(submessageArgs);
319 } else { // unrecognized submessage
320 NOTREACHED();
321 delete submessageArgs;
322 return;
324 delete submessageArgs;
326 // call BrowserBridge.onCallAsyncReply with result
327 if (ret) {
328 web_ui()->CallJavascriptFunction("browserBridge.onCallAsyncReply",
329 *requestId,
330 *ret);
331 delete ret;
332 } else {
333 web_ui()->CallJavascriptFunction("browserBridge.onCallAsyncReply",
334 *requestId);
338 void GpuMessageHandler::OnBrowserBridgeInitialized(
339 const base::ListValue* args) {
340 DCHECK_CURRENTLY_ON(BrowserThread::UI);
342 // Watch for changes in GPUInfo
343 if (!observing_) {
344 GpuDataManagerImpl::GetInstance()->AddObserver(this);
345 ui::GpuSwitchingManager::GetInstance()->AddObserver(this);
347 observing_ = true;
349 // Tell GpuDataManager it should have full GpuInfo. If the
350 // Gpu process has not run yet, this will trigger its launch.
351 GpuDataManagerImpl::GetInstance()->RequestCompleteGpuInfoIfNeeded();
353 // Run callback immediately in case the info is ready and no update in the
354 // future.
355 OnGpuInfoUpdate();
358 base::Value* GpuMessageHandler::OnRequestClientInfo(
359 const base::ListValue* list) {
360 DCHECK_CURRENTLY_ON(BrowserThread::UI);
362 base::DictionaryValue* dict = new base::DictionaryValue();
364 dict->SetString("version", GetContentClient()->GetProduct());
365 dict->SetString("command_line",
366 base::CommandLine::ForCurrentProcess()->GetCommandLineString());
367 dict->SetString("operating_system",
368 base::SysInfo::OperatingSystemName() + " " +
369 base::SysInfo::OperatingSystemVersion());
370 dict->SetString("angle_commit_id", ANGLE_COMMIT_HASH);
371 dict->SetString("graphics_backend", "Skia");
372 dict->SetString("blacklist_version",
373 GpuDataManagerImpl::GetInstance()->GetBlacklistVersion());
374 dict->SetString("driver_bug_list_version",
375 GpuDataManagerImpl::GetInstance()->GetDriverBugListVersion());
377 return dict;
380 base::Value* GpuMessageHandler::OnRequestLogMessages(const base::ListValue*) {
381 DCHECK_CURRENTLY_ON(BrowserThread::UI);
383 return GpuDataManagerImpl::GetInstance()->GetLogMessages();
386 void GpuMessageHandler::OnGpuInfoUpdate() {
387 // Get GPU Info.
388 scoped_ptr<base::DictionaryValue> gpu_info_val(GpuInfoAsDictionaryValue());
391 // Add in blacklisting features
392 base::DictionaryValue* feature_status = new base::DictionaryValue;
393 feature_status->Set("featureStatus", GetFeatureStatus());
394 feature_status->Set("problems", GetProblems());
395 base::ListValue* workarounds = new base::ListValue();
396 for (const std::string& workaround : GetDriverBugWorkarounds())
397 workarounds->AppendString(workaround);
398 feature_status->Set("workarounds", workarounds);
399 gpu_info_val->Set("featureStatus", feature_status);
401 // Send GPU Info to javascript.
402 web_ui()->CallJavascriptFunction("browserBridge.onGpuInfoUpdate",
403 *(gpu_info_val.get()));
406 void GpuMessageHandler::OnGpuSwitched() {
407 GpuDataManagerImpl::GetInstance()->RequestCompleteGpuInfoIfNeeded();
410 } // namespace
413 ////////////////////////////////////////////////////////////////////////////////
415 // GpuInternalsUI
417 ////////////////////////////////////////////////////////////////////////////////
419 GpuInternalsUI::GpuInternalsUI(WebUI* web_ui)
420 : WebUIController(web_ui) {
421 web_ui->AddMessageHandler(new GpuMessageHandler());
423 // Set up the chrome://gpu/ source.
424 BrowserContext* browser_context =
425 web_ui->GetWebContents()->GetBrowserContext();
426 WebUIDataSource::Add(browser_context, CreateGpuHTMLSource());
429 } // namespace content