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