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 // Factory for the creating refs in callbacks. 123 base::WeakPtrFactory<FlashDOMHandler> weak_ptr_factory_; 124 125 // Whether the list of all crashes is available. 126 bool crash_list_available_; 127 // Whether the page has requested data. 128 bool page_has_requested_data_; 129 // Whether the GPU data has been collected. 130 bool has_gpu_info_; 131 // Whether the plugin information is ready. 132 bool has_plugin_info_; 133 134 DISALLOW_COPY_AND_ASSIGN(FlashDOMHandler); 135 }; 136 137 FlashDOMHandler::FlashDOMHandler() 138 : weak_ptr_factory_(this), 139 crash_list_available_(false), 140 page_has_requested_data_(false), 141 has_gpu_info_(false), 142 has_plugin_info_(false) { 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(ListValue* list, const string16& key, const string16& value) { 185 DictionaryValue* results = new DictionaryValue(); 186 results->SetString("key", key); 187 results->SetString("value", value); 188 list->Append(results); 189 } 190 191 void AddPair(ListValue* list, const string16& key, const std::string& value) { 192 AddPair(list, key, ASCIIToUTF16(value)); 193 } 194 195 void FlashDOMHandler::HandleRequestFlashInfo(const ListValue* args) { 196 page_has_requested_data_ = true; 197 MaybeRespondToPage(); 198 } 199 200 void FlashDOMHandler::OnGpuInfoUpdate() { 201 has_gpu_info_ = true; 202 MaybeRespondToPage(); 203 } 204 205 void FlashDOMHandler::OnGotPlugins( 206 const std::vector<content::WebPluginInfo>& plugins) { 207 has_plugin_info_ = true; 208 MaybeRespondToPage(); 209 } 210 211 void FlashDOMHandler::OnTimeout() { 212 // We don't set page_has_requested_data_ because that is guaranteed to appear 213 // and we shouldn't be responding to the page before then. 214 has_gpu_info_ = true; 215 crash_list_available_ = true; 216 has_plugin_info_ = true; 217 MaybeRespondToPage(); 218 } 219 220 void FlashDOMHandler::MaybeRespondToPage() { 221 // We don't reply until everything is ready. The page is showing a 'loading' 222 // message until then. If you add criteria to this list, please update the 223 // function OnTimeout() as well. 224 if (!page_has_requested_data_ || !crash_list_available_ || !has_gpu_info_ || 225 !has_plugin_info_) { 226 return; 227 } 228 229 timeout_.Stop(); 230 231 // This is code that runs only when the user types in about:flash. We don't 232 // need to jump through hoops to offload this to the IO thread. 233 base::ThreadRestrictions::ScopedAllowIO allow_io; 234 235 // Obtain the Chrome version info. 236 chrome::VersionInfo version_info; 237 238 ListValue* list = new ListValue(); 239 240 // Chrome version information. 241 AddPair(list, 242 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME), 243 version_info.Version() + " (" + 244 chrome::VersionInfo::GetVersionStringModifier() + ")"); 245 246 // OS version information. 247 std::string os_label = version_info.OSType(); 248 #if defined(OS_WIN) 249 base::win::OSInfo* os = base::win::OSInfo::GetInstance(); 250 switch (os->version()) { 251 case base::win::VERSION_XP: os_label += " XP"; break; 252 case base::win::VERSION_SERVER_2003: 253 os_label += " Server 2003 or XP Pro 64 bit"; 254 break; 255 case base::win::VERSION_VISTA: os_label += " Vista or Server 2008"; break; 256 case base::win::VERSION_WIN7: os_label += " 7 or Server 2008 R2"; break; 257 case base::win::VERSION_WIN8: os_label += " 8 or Server 2012"; break; 258 default: os_label += " UNKNOWN"; break; 259 } 260 os_label += " SP" + base::IntToString(os->service_pack().major); 261 if (os->service_pack().minor > 0) 262 os_label += "." + base::IntToString(os->service_pack().minor); 263 if (os->architecture() == base::win::OSInfo::X64_ARCHITECTURE) 264 os_label += " 64 bit"; 265 #endif 266 AddPair(list, l10n_util::GetStringUTF16(IDS_ABOUT_VERSION_OS), os_label); 267 268 // Obtain the version of the Flash plugins. 269 std::vector<content::WebPluginInfo> info_array; 270 PluginService::GetInstance()->GetPluginInfoArray( 271 GURL(), content::kFlashPluginSwfMimeType, false, &info_array, NULL); 272 if (info_array.empty()) { 273 AddPair(list, ASCIIToUTF16(kFlashPlugin), "Not installed"); 274 } else { 275 PluginPrefs* plugin_prefs = 276 PluginPrefs::GetForProfile(Profile::FromWebUI(web_ui())).get(); 277 bool found_enabled = false; 278 for (size_t i = 0; i < info_array.size(); ++i) { 279 string16 flash_version = info_array[i].version + ASCIIToUTF16(" ") + 280 info_array[i].path.LossyDisplayName(); 281 if (plugin_prefs->IsPluginEnabled(info_array[i])) { 282 // If we have already found an enabled Flash version, this one 283 // is not used. 284 if (found_enabled) 285 flash_version += ASCIIToUTF16(" (not used)"); 286 287 found_enabled = true; 288 } else { 289 flash_version += ASCIIToUTF16(" (disabled)"); 290 } 291 AddPair(list, ASCIIToUTF16(kFlashPlugin), flash_version); 292 } 293 } 294 295 // Crash information. 296 AddPair(list, string16(), "--- Crash data ---"); 297 bool crash_reporting_enabled = CrashesUI::CrashReportingUIEnabled(); 298 if (crash_reporting_enabled) { 299 std::vector<CrashUploadList::UploadInfo> crashes; 300 upload_list_->GetUploads(10, &crashes); 301 302 for (std::vector<CrashUploadList::UploadInfo>::iterator i = crashes.begin(); 303 i != crashes.end(); ++i) { 304 string16 crash_string(ASCIIToUTF16(i->id)); 305 crash_string += ASCIIToUTF16(" "); 306 crash_string += base::TimeFormatFriendlyDateAndTime(i->time); 307 AddPair(list, ASCIIToUTF16("crash id"), crash_string); 308 } 309 } else { 310 AddPair(list, ASCIIToUTF16("Crash Reporting"), 311 "Enable crash reporting to see crash IDs"); 312 AddPair(list, ASCIIToUTF16("For more details"), 313 chrome::kLearnMoreReportingURL); 314 } 315 316 // GPU information. 317 AddPair(list, string16(), "--- GPU information ---"); 318 gpu::GPUInfo gpu_info = GpuDataManager::GetInstance()->GetGPUInfo(); 319 320 std::string reason; 321 if (!GpuDataManager::GetInstance()->GpuAccessAllowed(&reason)) { 322 AddPair(list, ASCIIToUTF16("WARNING:"), 323 "GPU access is not allowed: " + reason); 324 } 325 #if defined(OS_WIN) 326 const gpu::DxDiagNode& node = gpu_info.dx_diagnostics; 327 for (std::map<std::string, gpu::DxDiagNode>::const_iterator it = 328 node.children.begin(); 329 it != node.children.end(); 330 ++it) { 331 for (std::map<std::string, std::string>::const_iterator it2 = 332 it->second.values.begin(); 333 it2 != it->second.values.end(); 334 ++it2) { 335 if (!it2->second.empty()) { 336 if (it2->first == "szDescription") { 337 AddPair(list, ASCIIToUTF16("Graphics card"), it2->second); 338 } else if (it2->first == "szDriverNodeStrongName") { 339 AddPair(list, ASCIIToUTF16("Driver name (strong)"), it2->second); 340 } else if (it2->first == "szDriverName") { 341 AddPair(list, ASCIIToUTF16("Driver display name"), it2->second); 342 } 343 } 344 } 345 } 346 #endif 347 348 AddPair(list, string16(), "--- GPU driver, more information ---"); 349 AddPair(list, 350 ASCIIToUTF16("Vendor Id"), 351 base::StringPrintf("0x%04x", gpu_info.gpu.vendor_id)); 352 AddPair(list, 353 ASCIIToUTF16("Device Id"), 354 base::StringPrintf("0x%04x", gpu_info.gpu.device_id)); 355 AddPair(list, ASCIIToUTF16("Driver vendor"), gpu_info.driver_vendor); 356 AddPair(list, ASCIIToUTF16("Driver version"), gpu_info.driver_version); 357 AddPair(list, ASCIIToUTF16("Driver date"), gpu_info.driver_date); 358 AddPair(list, 359 ASCIIToUTF16("Pixel shader version"), 360 gpu_info.pixel_shader_version); 361 AddPair(list, 362 ASCIIToUTF16("Vertex shader version"), 363 gpu_info.vertex_shader_version); 364 AddPair(list, ASCIIToUTF16("GL version"), gpu_info.gl_version); 365 AddPair(list, ASCIIToUTF16("GL_VENDOR"), gpu_info.gl_vendor); 366 AddPair(list, ASCIIToUTF16("GL_RENDERER"), gpu_info.gl_renderer); 367 AddPair(list, ASCIIToUTF16("GL_VERSION"), gpu_info.gl_version_string); 368 AddPair(list, ASCIIToUTF16("GL_EXTENSIONS"), gpu_info.gl_extensions); 369 370 DictionaryValue flashInfo; 371 flashInfo.Set("flashInfo", list); 372 web_ui()->CallJavascriptFunction("returnFlashInfo", flashInfo); 373 } 374 375 } // namespace 376 377 /////////////////////////////////////////////////////////////////////////////// 378 // 379 // FlashUI 380 // 381 /////////////////////////////////////////////////////////////////////////////// 382 383 FlashUI::FlashUI(content::WebUI* web_ui) : WebUIController(web_ui) { 384 content::RecordAction( 385 UserMetricsAction("ViewAboutFlash")); 386 387 web_ui->AddMessageHandler(new FlashDOMHandler()); 388 389 // Set up the about:flash source. 390 Profile* profile = Profile::FromWebUI(web_ui); 391 content::WebUIDataSource::Add(profile, CreateFlashUIHTMLSource()); 392 } 393 394 // static 395 base::RefCountedMemory* FlashUI::GetFaviconResourceBytes( 396 ui::ScaleFactor scale_factor) { 397 // Use the default icon for now. 398 return NULL; 399 } 400