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/plugins/plugin_prefs.h" 24 #include "chrome/browser/profiles/profile.h" 25 #include "chrome/browser/ui/webui/crashes_ui.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 content::GpuDataManager; 51 using content::PluginService; 52 using content::UserMetricsAction; 53 using content::WebContents; 54 using content::WebUIMessageHandler; 55 56 namespace { 57 58 const char kFlashPlugin[] = "Flash plugin"; 59 60 content::WebUIDataSource* CreateFlashUIHTMLSource() { 61 content::WebUIDataSource* source = 62 content::WebUIDataSource::Create(chrome::kChromeUIFlashHost); 63 64 source->SetUseJsonJSFormatV2(); 65 source->AddLocalizedString("loadingMessage", IDS_FLASH_LOADING_MESSAGE); 66 source->AddLocalizedString("flashLongTitle", IDS_FLASH_TITLE_MESSAGE); 67 source->SetJsonPath("strings.js"); 68 source->AddResourcePath("about_flash.js", IDR_ABOUT_FLASH_JS); 69 source->SetDefaultResource(IDR_ABOUT_FLASH_HTML); 70 return source; 71 } 72 73 const int kTimeout = 8 * 1000; // 8 seconds. 74 75 //////////////////////////////////////////////////////////////////////////////// 76 // 77 // FlashDOMHandler 78 // 79 //////////////////////////////////////////////////////////////////////////////// 80 81 // The handler for JavaScript messages for the about:flags page. 82 class FlashDOMHandler : public WebUIMessageHandler, 83 public CrashUploadList::Delegate, 84 public content::GpuDataManagerObserver { 85 public: 86 FlashDOMHandler(); 87 virtual ~FlashDOMHandler(); 88 89 // WebUIMessageHandler implementation. 90 virtual void RegisterMessages() OVERRIDE; 91 92 // CrashUploadList::Delegate implementation. 93 virtual void OnUploadListAvailable() OVERRIDE; 94 95 // GpuDataManager::Observer implementation. 96 virtual void OnGpuInfoUpdate() OVERRIDE; 97 98 // Callback for the "requestFlashInfo" message. 99 void HandleRequestFlashInfo(const ListValue* args); 100 101 // Callback for the Flash plugin information. 102 void OnGotPlugins(const std::vector<content::WebPluginInfo>& plugins); 103 104 private: 105 // Called when we think we might have enough information to return data back 106 // to the page. 107 void MaybeRespondToPage(); 108 109 // In certain cases we might not get called back from the GPU process so we 110 // set an upper limit on the time we wait. This function gets called when the 111 // time has passed. This actually doesn't prevent the rest of the information 112 // to appear later, the page will just reflow when more information becomes 113 // available. 114 void OnTimeout(); 115 116 // A timer to keep track of when the data fetching times out. 117 base::OneShotTimer<FlashDOMHandler> timeout_; 118 119 // Crash list. 120 scoped_refptr<CrashUploadList> upload_list_; 121 122 // Whether the list of all crashes is available. 123 bool crash_list_available_; 124 // Whether the page has requested data. 125 bool page_has_requested_data_; 126 // Whether the GPU data has been collected. 127 bool has_gpu_info_; 128 // Whether the plugin information is ready. 129 bool has_plugin_info_; 130 131 base::WeakPtrFactory<FlashDOMHandler> weak_ptr_factory_; 132 133 DISALLOW_COPY_AND_ASSIGN(FlashDOMHandler); 134 }; 135 136 FlashDOMHandler::FlashDOMHandler() 137 : crash_list_available_(false), 138 page_has_requested_data_(false), 139 has_gpu_info_(false), 140 has_plugin_info_(false), 141 weak_ptr_factory_(this) { 142 // Request Crash data asynchronously. 143 upload_list_ = CrashUploadList::Create(this); 144 upload_list_->LoadUploadListAsynchronously(); 145 146 // Watch for changes in GPUInfo. 147 GpuDataManager::GetInstance()->AddObserver(this); 148 149 // Tell GpuDataManager it should have full GpuInfo. If the 150 // GPU process has not run yet, this will trigger its launch. 151 GpuDataManager::GetInstance()->RequestCompleteGpuInfoIfNeeded(); 152 153 // GPU access might not be allowed at all, which will cause us not to get a 154 // call back. 155 if (!GpuDataManager::GetInstance()->GpuAccessAllowed(NULL)) 156 OnGpuInfoUpdate(); 157 158 PluginService::GetInstance()->GetPlugins(base::Bind( 159 &FlashDOMHandler::OnGotPlugins, weak_ptr_factory_.GetWeakPtr())); 160 161 // And lastly, we fire off a timer to make sure we never get stuck at the 162 // "Loading..." message. 163 timeout_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(kTimeout), 164 this, &FlashDOMHandler::OnTimeout); 165 } 166 167 FlashDOMHandler::~FlashDOMHandler() { 168 GpuDataManager::GetInstance()->RemoveObserver(this); 169 upload_list_->ClearDelegate(); 170 } 171 172 void FlashDOMHandler::RegisterMessages() { 173 web_ui()->RegisterMessageCallback("requestFlashInfo", 174 base::Bind(&FlashDOMHandler::HandleRequestFlashInfo, 175 base::Unretained(this))); 176 } 177 178 void FlashDOMHandler::OnUploadListAvailable() { 179 crash_list_available_ = true; 180 MaybeRespondToPage(); 181 } 182 183 void AddPair(ListValue* list, 184 const base::string16& key, 185 const base::string16& value) { 186 DictionaryValue* results = new DictionaryValue(); 187 results->SetString("key", key); 188 results->SetString("value", value); 189 list->Append(results); 190 } 191 192 void AddPair(ListValue* list, 193 const base::string16& key, 194 const std::string& value) { 195 AddPair(list, key, ASCIIToUTF16(value)); 196 } 197 198 void FlashDOMHandler::HandleRequestFlashInfo(const ListValue* args) { 199 page_has_requested_data_ = true; 200 MaybeRespondToPage(); 201 } 202 203 void FlashDOMHandler::OnGpuInfoUpdate() { 204 has_gpu_info_ = true; 205 MaybeRespondToPage(); 206 } 207 208 void FlashDOMHandler::OnGotPlugins( 209 const std::vector<content::WebPluginInfo>& plugins) { 210 has_plugin_info_ = true; 211 MaybeRespondToPage(); 212 } 213 214 void FlashDOMHandler::OnTimeout() { 215 // We don't set page_has_requested_data_ because that is guaranteed to appear 216 // and we shouldn't be responding to the page before then. 217 has_gpu_info_ = true; 218 crash_list_available_ = true; 219 has_plugin_info_ = true; 220 MaybeRespondToPage(); 221 } 222 223 void FlashDOMHandler::MaybeRespondToPage() { 224 // We don't reply until everything is ready. The page is showing a 'loading' 225 // message until then. If you add criteria to this list, please update the 226 // function OnTimeout() as well. 227 if (!page_has_requested_data_ || !crash_list_available_ || !has_gpu_info_ || 228 !has_plugin_info_) { 229 return; 230 } 231 232 timeout_.Stop(); 233 234 // This is code that runs only when the user types in about:flash. We don't 235 // need to jump through hoops to offload this to the IO thread. 236 base::ThreadRestrictions::ScopedAllowIO allow_io; 237 238 // Obtain the Chrome version info. 239 chrome::VersionInfo version_info; 240 241 ListValue* list = new ListValue(); 242 243 // Chrome version information. 244 AddPair(list, 245 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME), 246 version_info.Version() + " (" + 247 chrome::VersionInfo::GetVersionStringModifier() + ")"); 248 249 // OS version information. 250 std::string os_label = version_info.OSType(); 251 #if defined(OS_WIN) 252 base::win::OSInfo* os = base::win::OSInfo::GetInstance(); 253 switch (os->version()) { 254 case base::win::VERSION_XP: os_label += " XP"; break; 255 case base::win::VERSION_SERVER_2003: 256 os_label += " Server 2003 or XP Pro 64 bit"; 257 break; 258 case base::win::VERSION_VISTA: os_label += " Vista or Server 2008"; break; 259 case base::win::VERSION_WIN7: os_label += " 7 or Server 2008 R2"; break; 260 case base::win::VERSION_WIN8: os_label += " 8 or Server 2012"; break; 261 default: os_label += " UNKNOWN"; break; 262 } 263 os_label += " SP" + base::IntToString(os->service_pack().major); 264 if (os->service_pack().minor > 0) 265 os_label += "." + base::IntToString(os->service_pack().minor); 266 if (os->architecture() == base::win::OSInfo::X64_ARCHITECTURE) 267 os_label += " 64 bit"; 268 #endif 269 AddPair(list, l10n_util::GetStringUTF16(IDS_ABOUT_VERSION_OS), os_label); 270 271 // Obtain the version of the Flash plugins. 272 std::vector<content::WebPluginInfo> info_array; 273 PluginService::GetInstance()->GetPluginInfoArray( 274 GURL(), content::kFlashPluginSwfMimeType, false, &info_array, NULL); 275 if (info_array.empty()) { 276 AddPair(list, ASCIIToUTF16(kFlashPlugin), "Not installed"); 277 } else { 278 PluginPrefs* plugin_prefs = 279 PluginPrefs::GetForProfile(Profile::FromWebUI(web_ui())).get(); 280 bool found_enabled = false; 281 for (size_t i = 0; i < info_array.size(); ++i) { 282 base::string16 flash_version = info_array[i].version + ASCIIToUTF16(" ") + 283 info_array[i].path.LossyDisplayName(); 284 if (plugin_prefs->IsPluginEnabled(info_array[i])) { 285 // If we have already found an enabled Flash version, this one 286 // is not used. 287 if (found_enabled) 288 flash_version += ASCIIToUTF16(" (not used)"); 289 290 found_enabled = true; 291 } else { 292 flash_version += ASCIIToUTF16(" (disabled)"); 293 } 294 AddPair(list, ASCIIToUTF16(kFlashPlugin), flash_version); 295 } 296 } 297 298 // Crash information. 299 AddPair(list, base::string16(), "--- Crash data ---"); 300 bool crash_reporting_enabled = CrashesUI::CrashReportingUIEnabled(); 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 version"), gpu_info.gl_version); 368 AddPair(list, ASCIIToUTF16("GL_VENDOR"), gpu_info.gl_vendor); 369 AddPair(list, ASCIIToUTF16("GL_RENDERER"), gpu_info.gl_renderer); 370 AddPair(list, ASCIIToUTF16("GL_VERSION"), gpu_info.gl_version_string); 371 AddPair(list, ASCIIToUTF16("GL_EXTENSIONS"), gpu_info.gl_extensions); 372 373 DictionaryValue flashInfo; 374 flashInfo.Set("flashInfo", list); 375 web_ui()->CallJavascriptFunction("returnFlashInfo", flashInfo); 376 } 377 378 } // namespace 379 380 /////////////////////////////////////////////////////////////////////////////// 381 // 382 // FlashUI 383 // 384 /////////////////////////////////////////////////////////////////////////////// 385 386 FlashUI::FlashUI(content::WebUI* web_ui) : WebUIController(web_ui) { 387 content::RecordAction( 388 UserMetricsAction("ViewAboutFlash")); 389 390 web_ui->AddMessageHandler(new FlashDOMHandler()); 391 392 // Set up the about:flash source. 393 Profile* profile = Profile::FromWebUI(web_ui); 394 content::WebUIDataSource::Add(profile, CreateFlashUIHTMLSource()); 395 } 396 397 // static 398 base::RefCountedMemory* FlashUI::GetFaviconResourceBytes( 399 ui::ScaleFactor scale_factor) { 400 // Use the default icon for now. 401 return NULL; 402 } 403