1 // Copyright 2014 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/devtools/protocol/system_info_handler.h"
8 #include "content/browser/gpu/compositor_util.h"
9 #include "content/public/browser/gpu_data_manager.h"
10 #include "gpu/config/gpu_info.h"
14 namespace system_info
{
18 using Response
= DevToolsProtocolClient::Response
;
20 // Give the GPU process a few seconds to provide GPU info.
21 const int kGPUInfoWatchdogTimeoutMs
= 5000;
23 class AuxGPUInfoEnumerator
: public gpu::GPUInfo::Enumerator
{
25 AuxGPUInfoEnumerator(base::DictionaryValue
* dictionary
)
26 : dictionary_(dictionary
),
27 in_aux_attributes_(false) { }
29 void AddInt64(const char* name
, int64 value
) override
{
30 if (in_aux_attributes_
)
31 dictionary_
->SetDouble(name
, value
);
34 void AddInt(const char* name
, int value
) override
{
35 if (in_aux_attributes_
)
36 dictionary_
->SetInteger(name
, value
);
39 void AddString(const char* name
, const std::string
& value
) override
{
40 if (in_aux_attributes_
)
41 dictionary_
->SetString(name
, value
);
44 void AddBool(const char* name
, bool value
) override
{
45 if (in_aux_attributes_
)
46 dictionary_
->SetBoolean(name
, value
);
49 void AddTimeDeltaInSecondsF(const char* name
,
50 const base::TimeDelta
& value
) override
{
51 if (in_aux_attributes_
)
52 dictionary_
->SetDouble(name
, value
.InSecondsF());
55 void BeginGPUDevice() override
{}
57 void EndGPUDevice() override
{}
59 void BeginVideoDecodeAcceleratorSupportedProfile() override
{}
61 void EndVideoDecodeAcceleratorSupportedProfile() override
{}
63 void BeginVideoEncodeAcceleratorSupportedProfile() override
{}
65 void EndVideoEncodeAcceleratorSupportedProfile() override
{}
67 void BeginAuxAttributes() override
{
68 in_aux_attributes_
= true;
71 void EndAuxAttributes() override
{
72 in_aux_attributes_
= false;
76 base::DictionaryValue
* dictionary_
;
77 bool in_aux_attributes_
;
80 scoped_refptr
<GPUDevice
> GPUDeviceToProtocol(
81 const gpu::GPUInfo::GPUDevice
& device
) {
82 return GPUDevice::Create()->set_vendor_id(device
.vendor_id
)
83 ->set_device_id(device
.device_id
)
84 ->set_vendor_string(device
.vendor_string
)
85 ->set_device_string(device
.device_string
);
90 class SystemInfoHandlerGpuObserver
: public content::GpuDataManagerObserver
{
92 SystemInfoHandlerGpuObserver(base::WeakPtr
<SystemInfoHandler
> handler
,
93 DevToolsCommandId command_id
)
95 command_id_(command_id
),
96 observer_id_(++next_observer_id_
)
99 handler_
->AddActiveObserverId(observer_id_
);
103 void OnGpuInfoUpdate() override
{
104 UnregisterAndSendResponse();
107 void OnGpuProcessCrashed(base::TerminationStatus exit_code
) override
{
108 UnregisterAndSendResponse();
111 void UnregisterAndSendResponse() {
112 GpuDataManager::GetInstance()->RemoveObserver(this);
113 if (handler_
.get()) {
114 if (handler_
->RemoveActiveObserverId(observer_id_
)) {
115 handler_
->SendGetInfoResponse(command_id_
);
121 int GetObserverId() {
126 base::WeakPtr
<SystemInfoHandler
> handler_
;
127 DevToolsCommandId command_id_
;
130 static int next_observer_id_
;
133 int SystemInfoHandlerGpuObserver::next_observer_id_
= 0;
135 SystemInfoHandler::SystemInfoHandler()
136 : weak_factory_(this) {
139 SystemInfoHandler::~SystemInfoHandler() {
142 void SystemInfoHandler::SetClient(scoped_ptr
<Client
> client
) {
143 client_
.swap(client
);
146 Response
SystemInfoHandler::GetInfo(DevToolsCommandId command_id
) {
148 if (!GpuDataManager::GetInstance()->GpuAccessAllowed(&reason
) ||
149 GpuDataManager::GetInstance()->IsEssentialGpuInfoAvailable()) {
150 // The GpuDataManager already has all of the information needed to make
151 // GPU-based blacklisting decisions. Post a task to give it to the
152 // client asynchronously.
154 // Waiting for complete GPU info in the if-test above seems to
155 // frequently hit internal timeouts in the launching of the unsandboxed
156 // GPU process in debug builds on Windows.
157 BrowserThread::PostTask(
160 base::Bind(&SystemInfoHandler::SendGetInfoResponse
,
161 weak_factory_
.GetWeakPtr(),
164 // We will be able to get more information from the GpuDataManager.
165 // Register a transient observer with it to call us back when the
166 // information is available.
167 SystemInfoHandlerGpuObserver
* observer
= new SystemInfoHandlerGpuObserver(
168 weak_factory_
.GetWeakPtr(), command_id
);
169 BrowserThread::PostDelayedTask(
172 base::Bind(&SystemInfoHandler::ObserverWatchdogCallback
,
173 weak_factory_
.GetWeakPtr(),
174 observer
->GetObserverId(),
176 base::TimeDelta::FromMilliseconds(kGPUInfoWatchdogTimeoutMs
));
177 GpuDataManager::GetInstance()->AddObserver(observer
);
178 // There's no other method available to request just essential GPU info.
179 GpuDataManager::GetInstance()->RequestCompleteGpuInfoIfNeeded();
182 return Response::OK();
185 void SystemInfoHandler::SendGetInfoResponse(DevToolsCommandId command_id
) {
186 gpu::GPUInfo gpu_info
= GpuDataManager::GetInstance()->GetGPUInfo();
187 std::vector
<scoped_refptr
<GPUDevice
>> devices
;
188 devices
.push_back(GPUDeviceToProtocol(gpu_info
.gpu
));
189 for (const auto& device
: gpu_info
.secondary_gpus
)
190 devices
.push_back(GPUDeviceToProtocol(device
));
192 scoped_ptr
<base::DictionaryValue
> aux_attributes(new base::DictionaryValue
);
193 AuxGPUInfoEnumerator
enumerator(aux_attributes
.get());
194 gpu_info
.EnumerateFields(&enumerator
);
196 scoped_refptr
<GPUInfo
> gpu
= GPUInfo::Create()
197 ->set_devices(devices
)
198 ->set_aux_attributes(aux_attributes
.Pass())
199 ->set_feature_status(make_scoped_ptr(GetFeatureStatus()))
200 ->set_driver_bug_workarounds(GetDriverBugWorkarounds());
202 client_
->SendGetInfoResponse(
204 GetInfoResponse::Create()->set_gpu(gpu
)
205 ->set_model_name(gpu_info
.machine_model_name
)
206 ->set_model_version(gpu_info
.machine_model_version
));
209 void SystemInfoHandler::AddActiveObserverId(int observer_id
) {
210 base::AutoLock
auto_lock(lock_
);
211 active_observers_
.insert(observer_id
);
214 bool SystemInfoHandler::RemoveActiveObserverId(int observer_id
) {
215 base::AutoLock
auto_lock(lock_
);
216 int num_removed
= active_observers_
.erase(observer_id
);
217 return (num_removed
!= 0);
220 void SystemInfoHandler::ObserverWatchdogCallback(int observer_id
,
221 DevToolsCommandId command_id
) {
222 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
223 if (RemoveActiveObserverId(observer_id
)) {
224 SendGetInfoResponse(command_id
);
225 // For the time being we want to know about this event in the test logs.
226 LOG(ERROR
) << "SystemInfoHandler: request for GPU info timed out!"
227 << " Most recent info sent.";
231 } // namespace system_info
232 } // namespace devtools
233 } // namespace content