OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2010 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 "chrome/browser/dom_ui/gpu_ui.h" |
| 6 |
| 7 #include <algorithm> |
| 8 #include <string> |
| 9 #include <utility> |
| 10 #include <vector> |
| 11 |
| 12 #include "app/l10n_util.h" |
| 13 #include "app/resource_bundle.h" |
| 14 #include "base/command_line.h" |
| 15 #include "base/file_util.h" |
| 16 #include "base/message_loop.h" |
| 17 #include "base/path_service.h" |
| 18 #include "base/singleton.h" |
| 19 #include "base/string_number_conversions.h" |
| 20 #include "base/string_piece.h" |
| 21 #include "base/utf_string_conversions.h" |
| 22 #include "base/values.h" |
| 23 #include "chrome/browser/browser_process.h" |
| 24 #include "chrome/browser/browser_thread.h" |
| 25 #include "chrome/browser/dom_ui/chrome_url_data_manager.h" |
| 26 #include "chrome/browser/gpu_process_host.h" |
| 27 #include "chrome/browser/gpu_process_host_ui_shim.h" |
| 28 #include "chrome/browser/io_thread.h" |
| 29 #include "chrome/browser/net/chrome_net_log.h" |
| 30 #include "chrome/browser/net/connection_tester.h" |
| 31 #include "chrome/browser/net/passive_log_collector.h" |
| 32 #include "chrome/browser/net/url_fixer_upper.h" |
| 33 #include "chrome/browser/platform_util.h" |
| 34 #include "chrome/browser/profile.h" |
| 35 #include "chrome/common/chrome_paths.h" |
| 36 #include "chrome/common/chrome_version_info.h" |
| 37 #include "chrome/common/net/url_request_context_getter.h" |
| 38 #include "chrome/common/url_constants.h" |
| 39 #include "grit/generated_resources.h" |
| 40 #include "grit/gpu_resources.h" |
| 41 #include "grit/net_internals_resources.h" |
| 42 #include "net/base/escape.h" |
| 43 #include "net/base/host_resolver_impl.h" |
| 44 #include "net/base/net_errors.h" |
| 45 #include "net/base/net_util.h" |
| 46 #include "net/base/sys_addrinfo.h" |
| 47 #include "net/disk_cache/disk_cache.h" |
| 48 #include "net/http/http_cache.h" |
| 49 #include "net/http/http_network_layer.h" |
| 50 #include "net/http/http_network_session.h" |
| 51 #include "net/http/http_proxy_client_socket_pool.h" |
| 52 #include "net/proxy/proxy_service.h" |
| 53 #include "net/socket/socks_client_socket_pool.h" |
| 54 #include "net/socket/ssl_client_socket_pool.h" |
| 55 #include "net/socket/tcp_client_socket_pool.h" |
| 56 #include "net/url_request/url_request_context.h" |
| 57 |
| 58 namespace { |
| 59 |
| 60 class GpuHTMLSource : public ChromeURLDataManager::DataSource { |
| 61 public: |
| 62 GpuHTMLSource(); |
| 63 |
| 64 // Called when the network layer has requested a resource underneath |
| 65 // the path we registered. |
| 66 virtual void StartDataRequest(const std::string& path, |
| 67 bool is_off_the_record, |
| 68 int request_id); |
| 69 virtual std::string GetMimeType(const std::string&) const; |
| 70 |
| 71 private: |
| 72 ~GpuHTMLSource() {} |
| 73 DISALLOW_COPY_AND_ASSIGN(GpuHTMLSource); |
| 74 }; |
| 75 |
| 76 // This class receives javascript messages from the renderer. |
| 77 // Note that the DOMUI infrastructure runs on the UI thread, therefore all of |
| 78 // this class's methods are expected to run on the UI thread. |
| 79 // |
| 80 // Since the network code we want to run lives on the IO thread, we proxy |
| 81 // everything over to GpuMessageHandler::IOThreadImpl, which runs |
| 82 // on the IO thread. |
| 83 // |
| 84 // TODO(eroman): Can we start on the IO thread to begin with? |
| 85 class GpuMessageHandler |
| 86 : public DOMMessageHandler, |
| 87 public base::SupportsWeakPtr<GpuMessageHandler> { |
| 88 public: |
| 89 GpuMessageHandler(); |
| 90 virtual ~GpuMessageHandler(); |
| 91 |
| 92 // DOMMessageHandler implementation. |
| 93 virtual DOMMessageHandler* Attach(DOMUI* dom_ui); |
| 94 virtual void RegisterMessages(); |
| 95 |
| 96 // Mesages |
| 97 void OnCallAsync(const ListValue* list); |
| 98 |
| 99 // Submessages dispatched from OnCallAsync |
| 100 Value* OnRequestGpuInfo(const ListValue* list); |
| 101 Value* OnRequestClientInfo(const ListValue* list); |
| 102 |
| 103 // Executes the javascript function |function_name| in the renderer, passing |
| 104 // it the argument |value|. |
| 105 void CallJavascriptFunction(const std::wstring& function_name, |
| 106 const Value* value); |
| 107 |
| 108 private: |
| 109 DISALLOW_COPY_AND_ASSIGN(GpuMessageHandler); |
| 110 bool collecting_graphics_info_; |
| 111 }; |
| 112 |
| 113 //////////////////////////////////////////////////////////////////////////////// |
| 114 // |
| 115 // GpuHTMLSource |
| 116 // |
| 117 //////////////////////////////////////////////////////////////////////////////// |
| 118 |
| 119 GpuHTMLSource::GpuHTMLSource() |
| 120 : DataSource(chrome::kChromeUIGpuHost, MessageLoop::current()) { |
| 121 } |
| 122 |
| 123 void GpuHTMLSource::StartDataRequest(const std::string& path, |
| 124 bool is_off_the_record, |
| 125 int request_id) { |
| 126 // The provided "path" may contain a fragment, or query section. We only |
| 127 // care about the path itself, and will disregard anything else. |
| 128 std::string filename = |
| 129 GURL(std::string("chrome://net/") + path).path().substr(1); |
| 130 |
| 131 // The source for the net internals page is flattened during compilation, so |
| 132 // the only resource that should legitimately be requested is the main file. |
| 133 // Note that users can type anything into the address bar, though, so we must |
| 134 // handle arbitrary input. |
| 135 if (filename.empty() || filename == "index.html") { |
| 136 scoped_refptr<RefCountedStaticMemory> bytes( |
| 137 ResourceBundle::GetSharedInstance().LoadDataResourceBytes( |
| 138 IDR_GPU_INDEX_HTML)); |
| 139 if (bytes && bytes->front()) { |
| 140 SendResponse(request_id, bytes); |
| 141 return; |
| 142 } |
| 143 } |
| 144 |
| 145 const std::string data_string("<p style='color:red'>Failed to read resource" + |
| 146 EscapeForHTML(filename) + "</p>"); |
| 147 scoped_refptr<RefCountedBytes> bytes(new RefCountedBytes); |
| 148 bytes->data.resize(data_string.size()); |
| 149 std::copy(data_string.begin(), data_string.end(), bytes->data.begin()); |
| 150 SendResponse(request_id, bytes); |
| 151 } |
| 152 |
| 153 std::string GpuHTMLSource::GetMimeType(const std::string&) const { |
| 154 return "text/html"; |
| 155 } |
| 156 |
| 157 //////////////////////////////////////////////////////////////////////////////// |
| 158 // |
| 159 // GpuMessageHandler |
| 160 // |
| 161 //////////////////////////////////////////////////////////////////////////////// |
| 162 |
| 163 GpuMessageHandler::GpuMessageHandler() |
| 164 : collecting_graphics_info_(false) { |
| 165 } |
| 166 |
| 167 GpuMessageHandler::~GpuMessageHandler() {} |
| 168 |
| 169 DOMMessageHandler* GpuMessageHandler::Attach(DOMUI* dom_ui) { |
| 170 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 171 DOMMessageHandler* result = DOMMessageHandler::Attach(dom_ui); |
| 172 return result; |
| 173 } |
| 174 |
| 175 /* BrowserBridge.callAsync.prepends a requestID to these messages. */ |
| 176 void GpuMessageHandler::RegisterMessages() { |
| 177 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 178 |
| 179 dom_ui_->RegisterMessageCallback( |
| 180 "callAsync", |
| 181 NewCallback(this, &GpuMessageHandler::OnCallAsync)); |
| 182 } |
| 183 |
| 184 void GpuMessageHandler::OnCallAsync(const ListValue* args) { |
| 185 DCHECK(args->GetSize() >= 2); |
| 186 // unpack args into requestId, submessage and submessageArgs |
| 187 bool ok; |
| 188 Value* requestId; |
| 189 ok = args->Get(0, &requestId); |
| 190 DCHECK(ok); |
| 191 |
| 192 std::string submessage; |
| 193 ok = args->GetString(1, &submessage); |
| 194 DCHECK(ok); |
| 195 |
| 196 ListValue* submessageArgs = new ListValue(); |
| 197 for (size_t i = 2; i < args->GetSize(); ++i) { |
| 198 Value* arg; |
| 199 ok = args->Get(i, &arg); |
| 200 DCHECK(ok); |
| 201 |
| 202 Value* argCopy = arg->DeepCopy(); |
| 203 submessageArgs->Append(argCopy); |
| 204 } |
| 205 |
| 206 // call the submessage handler |
| 207 Value* ret = NULL; |
| 208 if (submessage == "requestGpuInfo") { |
| 209 ret = OnRequestGpuInfo(submessageArgs); |
| 210 } else if (submessage == "requestClientInfo") { |
| 211 ret = OnRequestClientInfo(submessageArgs); |
| 212 } else { // unrecognized submessage |
| 213 DCHECK(FALSE); |
| 214 delete submessageArgs; |
| 215 return; |
| 216 } |
| 217 delete submessageArgs; |
| 218 |
| 219 // call BrowserBridge.onCallAsyncReply with result |
| 220 if (ret) { |
| 221 dom_ui_->CallJavascriptFunction(L"g_browser.onCallAsyncReply", |
| 222 *requestId, |
| 223 *ret); |
| 224 delete ret; |
| 225 } else { |
| 226 dom_ui_->CallJavascriptFunction(L"g_browser.onCallAsyncReply", |
| 227 *requestId); |
| 228 } |
| 229 } |
| 230 |
| 231 Value* GpuMessageHandler::OnRequestClientInfo(const ListValue* list) { |
| 232 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 233 |
| 234 DictionaryValue* dict = new DictionaryValue(); |
| 235 |
| 236 chrome::VersionInfo version_info; |
| 237 |
| 238 if (!version_info.is_valid()) { |
| 239 DLOG(ERROR) << "Unable to create chrome::VersionInfo"; |
| 240 } else { |
| 241 // We have everything we need to send the right values. |
| 242 dict->SetString("version", version_info.Version()); |
| 243 dict->SetString("cl", version_info.LastChange()); |
| 244 dict->SetString("version_mod", |
| 245 platform_util::GetVersionStringModifier()); |
| 246 dict->SetString("official", |
| 247 l10n_util::GetStringUTF16( |
| 248 version_info.IsOfficialBuild() ? |
| 249 IDS_ABOUT_VERSION_OFFICIAL |
| 250 : IDS_ABOUT_VERSION_UNOFFICIAL)); |
| 251 |
| 252 dict->SetString("command_line", |
| 253 CommandLine::ForCurrentProcess()->command_line_string()); |
| 254 } |
| 255 |
| 256 return dict; |
| 257 } |
| 258 |
| 259 |
| 260 #if defined(OS_WIN) |
| 261 // Output DxDiagNode tree as HTML tables and nested HTML unordered list |
| 262 // elements. |
| 263 DictionaryValue* DxDiagNodeToDict(const DxDiagNode& node) { |
| 264 DictionaryValue* dict = new DictionaryValue(); |
| 265 for (std::map<std::string, std::string>::const_iterator it = |
| 266 node.values.begin(); |
| 267 it != node.values.end(); |
| 268 ++it) { |
| 269 dict->SetString(EscapeForHTML(it->first), EscapeForHTML(it->second)); |
| 270 } |
| 271 |
| 272 for (std::map<std::string, DxDiagNode>::const_iterator it = |
| 273 node.children.begin(); |
| 274 it != node.children.end(); |
| 275 ++it) { |
| 276 DictionaryValue* subdict = DxDiagNodeToDict(it->second); |
| 277 dict->Set(EscapeForHTML(it->first), subdict); |
| 278 } |
| 279 return dict; |
| 280 } |
| 281 |
| 282 #endif // OS_WIN |
| 283 |
| 284 std::string VersionNumberToString(uint32 value) { |
| 285 int hi = (value >> 8) & 0xff; |
| 286 int low = value & 0xff; |
| 287 return base::IntToString(hi) + "." + base::IntToString(low); |
| 288 } |
| 289 |
| 290 DictionaryValue* GpuInfoToDict(const GPUInfo& gpu_info) { |
| 291 |
| 292 DictionaryValue* info = new DictionaryValue(); |
| 293 info->SetString("Initialization time", |
| 294 base::Int64ToString(gpu_info.initialization_time().InMilliseconds())); |
| 295 info->SetString("Vendor Id", |
| 296 base::StringPrintf("0x%04x", gpu_info.vendor_id())); |
| 297 info->SetString("Device Id", |
| 298 base::StringPrintf("0x%04x", gpu_info.device_id())); |
| 299 info->SetString("Driver version", |
| 300 WideToASCII(gpu_info.driver_version()).c_str()); |
| 301 info->SetString("Pixel shader version", |
| 302 VersionNumberToString(gpu_info.pixel_shader_version())); |
| 303 info->SetString("Vertex shader version", |
| 304 VersionNumberToString(gpu_info.vertex_shader_version())); |
| 305 info->SetString("GL version", VersionNumberToString(gpu_info.gl_version())); |
| 306 |
| 307 DictionaryValue* dict = new DictionaryValue(); |
| 308 dict->Set("Basic GPU Information", info); |
| 309 |
| 310 #if defined(OS_WIN) |
| 311 DictionaryValue* dx_info = DxDiagNodeToDict(gpu_info.dx_diagnostics()); |
| 312 dict->Set("DirectX diagnostics", dx_info); |
| 313 #endif |
| 314 |
| 315 return dict; |
| 316 } |
| 317 |
| 318 Value* GpuMessageHandler::OnRequestGpuInfo(const ListValue* list) { |
| 319 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 320 |
| 321 // Get GPU Info. |
| 322 GPUInfo gpu_info = GpuProcessHost::Get()->gpu_info(); |
| 323 |
| 324 std::string html; |
| 325 if (!gpu_info.initialized()) { |
| 326 if (!collecting_graphics_info_) { |
| 327 GpuProcessHostUIShim::Get()->CollectGraphicsInfoAsynchronously(); |
| 328 collecting_graphics_info_ = true; |
| 329 } |
| 330 return NULL; |
| 331 } else { |
| 332 collecting_graphics_info_ = false; |
| 333 |
| 334 return GpuInfoToDict(gpu_info); |
| 335 } |
| 336 } |
| 337 |
| 338 } // namespace |
| 339 |
| 340 |
| 341 //////////////////////////////////////////////////////////////////////////////// |
| 342 // |
| 343 // GpuUI |
| 344 // |
| 345 //////////////////////////////////////////////////////////////////////////////// |
| 346 |
| 347 GpuUI::GpuUI(TabContents* contents) : DOMUI(contents) { |
| 348 AddMessageHandler((new GpuMessageHandler())->Attach(this)); |
| 349 |
| 350 GpuHTMLSource* html_source = new GpuHTMLSource(); |
| 351 |
| 352 // Set up the chrome://gpu/ source. |
| 353 BrowserThread::PostTask( |
| 354 BrowserThread::IO, FROM_HERE, |
| 355 NewRunnableMethod( |
| 356 Singleton<ChromeURLDataManager>::get(), |
| 357 &ChromeURLDataManager::AddDataSource, |
| 358 make_scoped_refptr(html_source))); |
| 359 } |
OLD | NEW |