flash_ui.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
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 "chrome/browser/ui/webui/flash_ui.h" 6 7#include <map> 8#include <string> 9#include <vector> 10 11#include "base/bind.h" 12#include "base/bind_helpers.h" 13#include "base/i18n/time_formatting.h" 14#include "base/memory/weak_ptr.h" 15#include "base/strings/string16.h" 16#include "base/strings/string_number_conversions.h" 17#include "base/strings/stringprintf.h" 18#include "base/strings/utf_string_conversions.h" 19#include "base/threading/thread_restrictions.h" 20#include "base/timer/timer.h" 21#include "base/values.h" 22#include "chrome/browser/crash_upload_list.h" 23#include "chrome/browser/metrics/chrome_metrics_service_accessor.h" 24#include "chrome/browser/plugins/plugin_prefs.h" 25#include "chrome/browser/profiles/profile.h" 26#include "chrome/common/chrome_version_info.h" 27#include "chrome/common/url_constants.h" 28#include "chrome/grit/chromium_strings.h" 29#include "chrome/grit/generated_resources.h" 30#include "content/public/browser/gpu_data_manager.h" 31#include "content/public/browser/gpu_data_manager_observer.h" 32#include "content/public/browser/plugin_service.h" 33#include "content/public/browser/user_metrics.h" 34#include "content/public/browser/web_contents.h" 35#include "content/public/browser/web_ui.h" 36#include "content/public/browser/web_ui_data_source.h" 37#include "content/public/browser/web_ui_message_handler.h" 38#include "content/public/common/content_constants.h" 39#include "content/public/common/webplugininfo.h" 40#include "gpu/config/gpu_info.h" 41#include "grit/browser_resources.h" 42#include "ui/base/l10n/l10n_util.h" 43 44#if defined(OS_WIN) 45#include "base/win/windows_version.h" 46#endif 47 48using base::ASCIIToUTF16; 49using base::UserMetricsAction; 50using content::GpuDataManager; 51using content::PluginService; 52using content::WebContents; 53using content::WebUIMessageHandler; 54 55namespace { 56 57const char kFlashPlugin[] = "Flash plugin"; 58 59content::WebUIDataSource* CreateFlashUIHTMLSource() { 60 content::WebUIDataSource* source = 61 content::WebUIDataSource::Create(chrome::kChromeUIFlashHost); 62 63 source->SetUseJsonJSFormatV2(); 64 source->AddLocalizedString("loadingMessage", IDS_FLASH_LOADING_MESSAGE); 65 source->AddLocalizedString("flashLongTitle", IDS_FLASH_TITLE_MESSAGE); 66 source->SetJsonPath("strings.js"); 67 source->AddResourcePath("about_flash.js", IDR_ABOUT_FLASH_JS); 68 source->SetDefaultResource(IDR_ABOUT_FLASH_HTML); 69 return source; 70} 71 72const int kTimeout = 8 * 1000; // 8 seconds. 73 74//////////////////////////////////////////////////////////////////////////////// 75// 76// FlashDOMHandler 77// 78//////////////////////////////////////////////////////////////////////////////// 79 80// The handler for JavaScript messages for the about:flags page. 81class FlashDOMHandler : public WebUIMessageHandler, 82 public CrashUploadList::Delegate, 83 public content::GpuDataManagerObserver { 84 public: 85 FlashDOMHandler(); 86 virtual ~FlashDOMHandler(); 87 88 // WebUIMessageHandler implementation. 89 virtual void RegisterMessages() OVERRIDE; 90 91 // CrashUploadList::Delegate implementation. 92 virtual void OnUploadListAvailable() OVERRIDE; 93 94 // GpuDataManager::Observer implementation. 95 virtual void OnGpuInfoUpdate() OVERRIDE; 96 97 // Callback for the "requestFlashInfo" message. 98 void HandleRequestFlashInfo(const base::ListValue* args); 99 100 // Callback for the Flash plugin information. 101 void OnGotPlugins(const std::vector<content::WebPluginInfo>& plugins); 102 103 private: 104 // Called when we think we might have enough information to return data back 105 // to the page. 106 void MaybeRespondToPage(); 107 108 // In certain cases we might not get called back from the GPU process so we 109 // set an upper limit on the time we wait. This function gets called when the 110 // time has passed. This actually doesn't prevent the rest of the information 111 // to appear later, the page will just reflow when more information becomes 112 // available. 113 void OnTimeout(); 114 115 // A timer to keep track of when the data fetching times out. 116 base::OneShotTimer<FlashDOMHandler> timeout_; 117 118 // Crash list. 119 scoped_refptr<CrashUploadList> upload_list_; 120 121 // Whether the list of all crashes is available. 122 bool crash_list_available_; 123 // Whether the page has requested data. 124 bool page_has_requested_data_; 125 // Whether the GPU data has been collected. 126 bool has_gpu_info_; 127 // Whether the plugin information is ready. 128 bool has_plugin_info_; 129 130 base::WeakPtrFactory<FlashDOMHandler> weak_ptr_factory_; 131 132 DISALLOW_COPY_AND_ASSIGN(FlashDOMHandler); 133}; 134 135FlashDOMHandler::FlashDOMHandler() 136 : crash_list_available_(false), 137 page_has_requested_data_(false), 138 has_gpu_info_(false), 139 has_plugin_info_(false), 140 weak_ptr_factory_(this) { 141 // Request Crash data asynchronously. 142 upload_list_ = CrashUploadList::Create(this); 143 upload_list_->LoadUploadListAsynchronously(); 144 145 // Watch for changes in GPUInfo. 146 GpuDataManager::GetInstance()->AddObserver(this); 147 148 // Tell GpuDataManager it should have full GpuInfo. If the 149 // GPU process has not run yet, this will trigger its launch. 150 GpuDataManager::GetInstance()->RequestCompleteGpuInfoIfNeeded(); 151 152 // GPU access might not be allowed at all, which will cause us not to get a 153 // call back. 154 if (!GpuDataManager::GetInstance()->GpuAccessAllowed(NULL)) 155 OnGpuInfoUpdate(); 156 157 PluginService::GetInstance()->GetPlugins(base::Bind( 158 &FlashDOMHandler::OnGotPlugins, weak_ptr_factory_.GetWeakPtr())); 159 160 // And lastly, we fire off a timer to make sure we never get stuck at the 161 // "Loading..." message. 162 timeout_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(kTimeout), 163 this, &FlashDOMHandler::OnTimeout); 164} 165 166FlashDOMHandler::~FlashDOMHandler() { 167 GpuDataManager::GetInstance()->RemoveObserver(this); 168 upload_list_->ClearDelegate(); 169} 170 171void FlashDOMHandler::RegisterMessages() { 172 web_ui()->RegisterMessageCallback("requestFlashInfo", 173 base::Bind(&FlashDOMHandler::HandleRequestFlashInfo, 174 base::Unretained(this))); 175} 176 177void FlashDOMHandler::OnUploadListAvailable() { 178 crash_list_available_ = true; 179 MaybeRespondToPage(); 180} 181 182void AddPair(base::ListValue* list, 183 const base::string16& key, 184 const base::string16& value) { 185 base::DictionaryValue* results = new base::DictionaryValue(); 186 results->SetString("key", key); 187 results->SetString("value", value); 188 list->Append(results); 189} 190 191void AddPair(base::ListValue* list, 192 const base::string16& key, 193 const std::string& value) { 194 AddPair(list, key, ASCIIToUTF16(value)); 195} 196 197void FlashDOMHandler::HandleRequestFlashInfo(const base::ListValue* args) { 198 page_has_requested_data_ = true; 199 MaybeRespondToPage(); 200} 201 202void FlashDOMHandler::OnGpuInfoUpdate() { 203 has_gpu_info_ = true; 204 MaybeRespondToPage(); 205} 206 207void FlashDOMHandler::OnGotPlugins( 208 const std::vector<content::WebPluginInfo>& plugins) { 209 has_plugin_info_ = true; 210 MaybeRespondToPage(); 211} 212 213void FlashDOMHandler::OnTimeout() { 214 // We don't set page_has_requested_data_ because that is guaranteed to appear 215 // and we shouldn't be responding to the page before then. 216 has_gpu_info_ = true; 217 crash_list_available_ = true; 218 has_plugin_info_ = true; 219 MaybeRespondToPage(); 220} 221 222void FlashDOMHandler::MaybeRespondToPage() { 223 // We don't reply until everything is ready. The page is showing a 'loading' 224 // message until then. If you add criteria to this list, please update the 225 // function OnTimeout() as well. 226 if (!page_has_requested_data_ || !crash_list_available_ || !has_gpu_info_ || 227 !has_plugin_info_) { 228 return; 229 } 230 231 timeout_.Stop(); 232 233 // This is code that runs only when the user types in about:flash. We don't 234 // need to jump through hoops to offload this to the IO thread. 235 base::ThreadRestrictions::ScopedAllowIO allow_io; 236 237 // Obtain the Chrome version info. 238 chrome::VersionInfo version_info; 239 240 base::ListValue* list = new base::ListValue(); 241 242 // Chrome version information. 243 AddPair(list, 244 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME), 245 version_info.Version() + " (" + 246 chrome::VersionInfo::GetVersionStringModifier() + ")"); 247 248 // OS version information. 249 std::string os_label = version_info.OSType(); 250#if defined(OS_WIN) 251 base::win::OSInfo* os = base::win::OSInfo::GetInstance(); 252 switch (os->version()) { 253 case base::win::VERSION_XP: os_label += " XP"; break; 254 case base::win::VERSION_SERVER_2003: 255 os_label += " Server 2003 or XP Pro 64 bit"; 256 break; 257 case base::win::VERSION_VISTA: os_label += " Vista or Server 2008"; break; 258 case base::win::VERSION_WIN7: os_label += " 7 or Server 2008 R2"; break; 259 case base::win::VERSION_WIN8: os_label += " 8 or Server 2012"; break; 260 default: os_label += " UNKNOWN"; break; 261 } 262 os_label += " SP" + base::IntToString(os->service_pack().major); 263 if (os->service_pack().minor > 0) 264 os_label += "." + base::IntToString(os->service_pack().minor); 265 if (os->architecture() == base::win::OSInfo::X64_ARCHITECTURE) 266 os_label += " 64 bit"; 267#endif 268 AddPair(list, l10n_util::GetStringUTF16(IDS_ABOUT_VERSION_OS), os_label); 269 270 // Obtain the version of the Flash plugins. 271 std::vector<content::WebPluginInfo> info_array; 272 PluginService::GetInstance()->GetPluginInfoArray( 273 GURL(), content::kFlashPluginSwfMimeType, false, &info_array, NULL); 274 if (info_array.empty()) { 275 AddPair(list, ASCIIToUTF16(kFlashPlugin), "Not installed"); 276 } else { 277 PluginPrefs* plugin_prefs = 278 PluginPrefs::GetForProfile(Profile::FromWebUI(web_ui())).get(); 279 bool found_enabled = false; 280 for (size_t i = 0; i < info_array.size(); ++i) { 281 base::string16 flash_version = info_array[i].version + ASCIIToUTF16(" ") + 282 info_array[i].path.LossyDisplayName(); 283 if (plugin_prefs->IsPluginEnabled(info_array[i])) { 284 // If we have already found an enabled Flash version, this one 285 // is not used. 286 if (found_enabled) 287 flash_version += ASCIIToUTF16(" (not used)"); 288 289 found_enabled = true; 290 } else { 291 flash_version += ASCIIToUTF16(" (disabled)"); 292 } 293 AddPair(list, ASCIIToUTF16(kFlashPlugin), flash_version); 294 } 295 } 296 297 // Crash information. 298 AddPair(list, base::string16(), "--- Crash data ---"); 299 bool crash_reporting_enabled = 300 ChromeMetricsServiceAccessor::IsCrashReportingEnabled(); 301 if (crash_reporting_enabled) { 302 std::vector<CrashUploadList::UploadInfo> crashes; 303 upload_list_->GetUploads(10, &crashes); 304 305 for (std::vector<CrashUploadList::UploadInfo>::iterator i = crashes.begin(); 306 i != crashes.end(); ++i) { 307 base::string16 crash_string(ASCIIToUTF16(i->id)); 308 crash_string += ASCIIToUTF16(" "); 309 crash_string += base::TimeFormatFriendlyDateAndTime(i->time); 310 AddPair(list, ASCIIToUTF16("crash id"), crash_string); 311 } 312 } else { 313 AddPair(list, ASCIIToUTF16("Crash Reporting"), 314 "Enable crash reporting to see crash IDs"); 315 AddPair(list, ASCIIToUTF16("For more details"), 316 chrome::kLearnMoreReportingURL); 317 } 318 319 // GPU information. 320 AddPair(list, base::string16(), "--- GPU information ---"); 321 gpu::GPUInfo gpu_info = GpuDataManager::GetInstance()->GetGPUInfo(); 322 323 std::string reason; 324 if (!GpuDataManager::GetInstance()->GpuAccessAllowed(&reason)) { 325 AddPair(list, ASCIIToUTF16("WARNING:"), 326 "GPU access is not allowed: " + reason); 327 } 328#if defined(OS_WIN) 329 const gpu::DxDiagNode& node = gpu_info.dx_diagnostics; 330 for (std::map<std::string, gpu::DxDiagNode>::const_iterator it = 331 node.children.begin(); 332 it != node.children.end(); 333 ++it) { 334 for (std::map<std::string, std::string>::const_iterator it2 = 335 it->second.values.begin(); 336 it2 != it->second.values.end(); 337 ++it2) { 338 if (!it2->second.empty()) { 339 if (it2->first == "szDescription") { 340 AddPair(list, ASCIIToUTF16("Graphics card"), it2->second); 341 } else if (it2->first == "szDriverNodeStrongName") { 342 AddPair(list, ASCIIToUTF16("Driver name (strong)"), it2->second); 343 } else if (it2->first == "szDriverName") { 344 AddPair(list, ASCIIToUTF16("Driver display name"), it2->second); 345 } 346 } 347 } 348 } 349#endif 350 351 AddPair(list, base::string16(), "--- GPU driver, more information ---"); 352 AddPair(list, 353 ASCIIToUTF16("Vendor Id"), 354 base::StringPrintf("0x%04x", gpu_info.gpu.vendor_id)); 355 AddPair(list, 356 ASCIIToUTF16("Device Id"), 357 base::StringPrintf("0x%04x", gpu_info.gpu.device_id)); 358 AddPair(list, ASCIIToUTF16("Driver vendor"), gpu_info.driver_vendor); 359 AddPair(list, ASCIIToUTF16("Driver version"), gpu_info.driver_version); 360 AddPair(list, ASCIIToUTF16("Driver date"), gpu_info.driver_date); 361 AddPair(list, 362 ASCIIToUTF16("Pixel shader version"), 363 gpu_info.pixel_shader_version); 364 AddPair(list, 365 ASCIIToUTF16("Vertex shader version"), 366 gpu_info.vertex_shader_version); 367 AddPair(list, ASCIIToUTF16("GL_VENDOR"), gpu_info.gl_vendor); 368 AddPair(list, ASCIIToUTF16("GL_RENDERER"), gpu_info.gl_renderer); 369 AddPair(list, ASCIIToUTF16("GL_VERSION"), gpu_info.gl_version); 370 AddPair(list, ASCIIToUTF16("GL_EXTENSIONS"), gpu_info.gl_extensions); 371 372 base::DictionaryValue flashInfo; 373 flashInfo.Set("flashInfo", list); 374 web_ui()->CallJavascriptFunction("returnFlashInfo", flashInfo); 375} 376 377} // namespace 378 379/////////////////////////////////////////////////////////////////////////////// 380// 381// FlashUI 382// 383/////////////////////////////////////////////////////////////////////////////// 384 385FlashUI::FlashUI(content::WebUI* web_ui) : WebUIController(web_ui) { 386 content::RecordAction( 387 UserMetricsAction("ViewAboutFlash")); 388 389 web_ui->AddMessageHandler(new FlashDOMHandler()); 390 391 // Set up the about:flash source. 392 Profile* profile = Profile::FromWebUI(web_ui); 393 content::WebUIDataSource::Add(profile, CreateFlashUIHTMLSource()); 394} 395 396// static 397base::RefCountedMemory* FlashUI::GetFaviconResourceBytes( 398 ui::ScaleFactor scale_factor) { 399 // Use the default icon for now. 400 return NULL; 401} 402