1 // Copyright (c) 2011 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/renderer/plugins/plugin_uma.h" 6 7 #include <algorithm> 8 #include <cstring> 9 10 #include "base/metrics/histogram.h" 11 #include "base/strings/string_util.h" 12 #include "content/public/common/content_constants.h" 13 #include "third_party/widevine/cdm/widevine_cdm_common.h" 14 15 namespace { 16 17 // String we will use to convert mime type to plugin type. 18 const char kWindowsMediaPlayerType[] = "application/x-mplayer2"; 19 const char kSilverlightTypePrefix[] = "application/x-silverlight"; 20 const char kRealPlayerTypePrefix[] = "audio/x-pn-realaudio"; 21 const char kJavaTypeSubstring[] = "application/x-java-applet"; 22 const char kQuickTimeType[] = "video/quicktime"; 23 24 // Arrays containing file extensions connected with specific plugins. 25 // Note: THE ARRAYS MUST BE SORTED BECAUSE BINARY SEARCH IS USED ON THEM! 26 const char* kWindowsMediaPlayerExtensions[] = { 27 ".asx" 28 }; 29 30 const char* kRealPlayerExtensions[] = { 31 ".ra", 32 ".ram", 33 ".rm", 34 ".rmm", 35 ".rmp", 36 ".rpm" 37 }; 38 39 const char* kQuickTimeExtensions[] = { 40 ".moov", 41 ".mov", 42 ".qif", 43 ".qt", 44 ".qti", 45 ".qtif" 46 }; 47 48 const char* kShockwaveFlashExtensions[] = { 49 ".spl", 50 ".swf" 51 }; 52 53 } // namespace. 54 55 class UMASenderImpl : public PluginUMAReporter::UMASender { 56 virtual void SendPluginUMA( 57 PluginUMAReporter::ReportType report_type, 58 PluginUMAReporter::PluginType plugin_type) OVERRIDE; 59 }; 60 61 void UMASenderImpl::SendPluginUMA(PluginUMAReporter::ReportType report_type, 62 PluginUMAReporter::PluginType plugin_type) { 63 // UMA_HISTOGRAM_ENUMERATION requires constant histogram name. Use string 64 // constants explicitly instead of trying to use variables for names. 65 switch (report_type) { 66 case PluginUMAReporter::MISSING_PLUGIN: 67 UMA_HISTOGRAM_ENUMERATION("Plugin.MissingPlugins", 68 plugin_type, 69 PluginUMAReporter::PLUGIN_TYPE_MAX); 70 break; 71 case PluginUMAReporter::DISABLED_PLUGIN: 72 UMA_HISTOGRAM_ENUMERATION("Plugin.DisabledPlugins", 73 plugin_type, 74 PluginUMAReporter::PLUGIN_TYPE_MAX); 75 break; 76 default: 77 NOTREACHED(); 78 } 79 } 80 81 // static. 82 PluginUMAReporter* PluginUMAReporter::GetInstance() { 83 return Singleton<PluginUMAReporter>::get(); 84 } 85 86 void PluginUMAReporter::ReportPluginMissing( 87 const std::string& plugin_mime_type, const GURL& plugin_src) { 88 report_sender_->SendPluginUMA(MISSING_PLUGIN, 89 GetPluginType(plugin_mime_type, plugin_src)); 90 } 91 92 void PluginUMAReporter::ReportPluginDisabled( 93 const std::string& plugin_mime_type, const GURL& plugin_src) { 94 report_sender_->SendPluginUMA(DISABLED_PLUGIN, 95 GetPluginType(plugin_mime_type, plugin_src)); 96 } 97 98 PluginUMAReporter::PluginUMAReporter() : report_sender_(new UMASenderImpl()) { 99 } 100 101 PluginUMAReporter::~PluginUMAReporter() { 102 } 103 104 // static. 105 bool PluginUMAReporter::CompareCStrings(const char* first, const char* second) { 106 return strcmp(first, second) < 0; 107 } 108 109 bool PluginUMAReporter::CStringArrayContainsCString(const char** array, 110 size_t array_size, 111 const char* str) { 112 return std::binary_search(array, array + array_size, str, CompareCStrings); 113 } 114 115 void PluginUMAReporter::ExtractFileExtension(const GURL& src, 116 std::string* extension) { 117 std::string extension_file_path(src.ExtractFileName()); 118 if (extension_file_path.empty()) 119 extension_file_path = src.host(); 120 121 size_t last_dot = extension_file_path.find_last_of('.'); 122 if (last_dot != std::string::npos) { 123 *extension = extension_file_path.substr(last_dot); 124 } else { 125 extension->clear(); 126 } 127 128 StringToLowerASCII(extension); 129 } 130 131 PluginUMAReporter::PluginType PluginUMAReporter::GetPluginType( 132 const std::string& plugin_mime_type, const GURL& plugin_src) { 133 // If we know plugin's mime type, we use it to determine plugin's type. Else, 134 // we try to determine plugin type using plugin source's extension. 135 if (!plugin_mime_type.empty()) 136 return MimeTypeToPluginType(StringToLowerASCII(plugin_mime_type)); 137 138 return SrcToPluginType(plugin_src); 139 } 140 141 PluginUMAReporter::PluginType PluginUMAReporter::SrcToPluginType( 142 const GURL& src) { 143 std::string file_extension; 144 ExtractFileExtension(src, &file_extension); 145 if (CStringArrayContainsCString(kWindowsMediaPlayerExtensions, 146 arraysize(kWindowsMediaPlayerExtensions), 147 file_extension.c_str())) { 148 return WINDOWS_MEDIA_PLAYER; 149 } 150 151 if (CStringArrayContainsCString(kQuickTimeExtensions, 152 arraysize(kQuickTimeExtensions), 153 file_extension.c_str())) { 154 return QUICKTIME; 155 } 156 157 if (CStringArrayContainsCString(kRealPlayerExtensions, 158 arraysize(kRealPlayerExtensions), 159 file_extension.c_str())) { 160 return REALPLAYER; 161 } 162 163 if (CStringArrayContainsCString(kShockwaveFlashExtensions, 164 arraysize(kShockwaveFlashExtensions), 165 file_extension.c_str())) { 166 return SHOCKWAVE_FLASH; 167 } 168 169 return UNSUPPORTED_EXTENSION; 170 } 171 172 PluginUMAReporter::PluginType PluginUMAReporter::MimeTypeToPluginType( 173 const std::string& mime_type) { 174 if (mime_type == kWindowsMediaPlayerType) 175 return WINDOWS_MEDIA_PLAYER; 176 177 size_t prefix_length = strlen(kSilverlightTypePrefix); 178 if (strncmp(mime_type.c_str(), kSilverlightTypePrefix, prefix_length) == 0) 179 return SILVERLIGHT; 180 181 prefix_length = strlen(kRealPlayerTypePrefix); 182 if (strncmp(mime_type.c_str(), kRealPlayerTypePrefix, prefix_length) == 0) 183 return REALPLAYER; 184 185 if (strstr(mime_type.c_str(), kJavaTypeSubstring)) 186 return JAVA; 187 188 if (mime_type == kQuickTimeType) 189 return QUICKTIME; 190 191 if (mime_type == content::kBrowserPluginMimeType) 192 return BROWSER_PLUGIN; 193 194 if (mime_type == content::kFlashPluginSwfMimeType || 195 mime_type == content::kFlashPluginSplMimeType) { 196 return SHOCKWAVE_FLASH; 197 } 198 199 #if defined(ENABLE_PEPPER_CDMS) 200 if (mime_type == kWidevineCdmPluginMimeType) 201 return WIDEVINE_CDM; 202 #endif 203 204 return UNSUPPORTED_MIMETYPE; 205 } 206