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[] = {".asx"};
27
28 const char* kRealPlayerExtensions[] = {".ra", ".ram", ".rm",
29 ".rmm", ".rmp", ".rpm"};
30
31 const char* kQuickTimeExtensions[] = {".moov", ".mov", ".qif",
32 ".qt", ".qti", ".qtif"};
33
34 const char* kShockwaveFlashExtensions[] = {".spl", ".swf"};
35
36 } // namespace.
37
38 class UMASenderImpl : public PluginUMAReporter::UMASender {
39 virtual void SendPluginUMA(
40 PluginUMAReporter::ReportType report_type,
41 PluginUMAReporter::PluginType plugin_type) OVERRIDE;
42 };
43
SendPluginUMA(PluginUMAReporter::ReportType report_type,PluginUMAReporter::PluginType plugin_type)44 void UMASenderImpl::SendPluginUMA(PluginUMAReporter::ReportType report_type,
45 PluginUMAReporter::PluginType plugin_type) {
46 // UMA_HISTOGRAM_ENUMERATION requires constant histogram name. Use string
47 // constants explicitly instead of trying to use variables for names.
48 switch (report_type) {
49 case PluginUMAReporter::MISSING_PLUGIN:
50 UMA_HISTOGRAM_ENUMERATION("Plugin.MissingPlugins",
51 plugin_type,
52 PluginUMAReporter::PLUGIN_TYPE_MAX);
53 break;
54 case PluginUMAReporter::DISABLED_PLUGIN:
55 UMA_HISTOGRAM_ENUMERATION("Plugin.DisabledPlugins",
56 plugin_type,
57 PluginUMAReporter::PLUGIN_TYPE_MAX);
58 break;
59 default:
60 NOTREACHED();
61 }
62 }
63
64 // static.
GetInstance()65 PluginUMAReporter* PluginUMAReporter::GetInstance() {
66 return Singleton<PluginUMAReporter>::get();
67 }
68
ReportPluginMissing(const std::string & plugin_mime_type,const GURL & plugin_src)69 void PluginUMAReporter::ReportPluginMissing(const std::string& plugin_mime_type,
70 const GURL& plugin_src) {
71 report_sender_->SendPluginUMA(MISSING_PLUGIN,
72 GetPluginType(plugin_mime_type, plugin_src));
73 }
74
ReportPluginDisabled(const std::string & plugin_mime_type,const GURL & plugin_src)75 void PluginUMAReporter::ReportPluginDisabled(
76 const std::string& plugin_mime_type,
77 const GURL& plugin_src) {
78 report_sender_->SendPluginUMA(DISABLED_PLUGIN,
79 GetPluginType(plugin_mime_type, plugin_src));
80 }
81
PluginUMAReporter()82 PluginUMAReporter::PluginUMAReporter() : report_sender_(new UMASenderImpl()) {}
83
~PluginUMAReporter()84 PluginUMAReporter::~PluginUMAReporter() {}
85
86 // static.
CompareCStrings(const char * first,const char * second)87 bool PluginUMAReporter::CompareCStrings(const char* first, const char* second) {
88 return strcmp(first, second) < 0;
89 }
90
CStringArrayContainsCString(const char ** array,size_t array_size,const char * str)91 bool PluginUMAReporter::CStringArrayContainsCString(const char** array,
92 size_t array_size,
93 const char* str) {
94 return std::binary_search(array, array + array_size, str, CompareCStrings);
95 }
96
ExtractFileExtension(const GURL & src,std::string * extension)97 void PluginUMAReporter::ExtractFileExtension(const GURL& src,
98 std::string* extension) {
99 std::string extension_file_path(src.ExtractFileName());
100 if (extension_file_path.empty())
101 extension_file_path = src.host();
102
103 size_t last_dot = extension_file_path.find_last_of('.');
104 if (last_dot != std::string::npos) {
105 *extension = extension_file_path.substr(last_dot);
106 } else {
107 extension->clear();
108 }
109
110 base::StringToLowerASCII(extension);
111 }
112
GetPluginType(const std::string & plugin_mime_type,const GURL & plugin_src)113 PluginUMAReporter::PluginType PluginUMAReporter::GetPluginType(
114 const std::string& plugin_mime_type,
115 const GURL& plugin_src) {
116 // If we know plugin's mime type, we use it to determine plugin's type. Else,
117 // we try to determine plugin type using plugin source's extension.
118 if (!plugin_mime_type.empty())
119 return MimeTypeToPluginType(base::StringToLowerASCII(plugin_mime_type));
120
121 return SrcToPluginType(plugin_src);
122 }
123
SrcToPluginType(const GURL & src)124 PluginUMAReporter::PluginType PluginUMAReporter::SrcToPluginType(
125 const GURL& src) {
126 std::string file_extension;
127 ExtractFileExtension(src, &file_extension);
128 if (CStringArrayContainsCString(kWindowsMediaPlayerExtensions,
129 arraysize(kWindowsMediaPlayerExtensions),
130 file_extension.c_str())) {
131 return WINDOWS_MEDIA_PLAYER;
132 }
133
134 if (CStringArrayContainsCString(kQuickTimeExtensions,
135 arraysize(kQuickTimeExtensions),
136 file_extension.c_str())) {
137 return QUICKTIME;
138 }
139
140 if (CStringArrayContainsCString(kRealPlayerExtensions,
141 arraysize(kRealPlayerExtensions),
142 file_extension.c_str())) {
143 return REALPLAYER;
144 }
145
146 if (CStringArrayContainsCString(kShockwaveFlashExtensions,
147 arraysize(kShockwaveFlashExtensions),
148 file_extension.c_str())) {
149 return SHOCKWAVE_FLASH;
150 }
151
152 return UNSUPPORTED_EXTENSION;
153 }
154
MimeTypeToPluginType(const std::string & mime_type)155 PluginUMAReporter::PluginType PluginUMAReporter::MimeTypeToPluginType(
156 const std::string& mime_type) {
157 if (mime_type == kWindowsMediaPlayerType)
158 return WINDOWS_MEDIA_PLAYER;
159
160 size_t prefix_length = strlen(kSilverlightTypePrefix);
161 if (strncmp(mime_type.c_str(), kSilverlightTypePrefix, prefix_length) == 0)
162 return SILVERLIGHT;
163
164 prefix_length = strlen(kRealPlayerTypePrefix);
165 if (strncmp(mime_type.c_str(), kRealPlayerTypePrefix, prefix_length) == 0)
166 return REALPLAYER;
167
168 if (strstr(mime_type.c_str(), kJavaTypeSubstring))
169 return JAVA;
170
171 if (mime_type == kQuickTimeType)
172 return QUICKTIME;
173
174 if (mime_type == content::kBrowserPluginMimeType)
175 return BROWSER_PLUGIN;
176
177 if (mime_type == content::kFlashPluginSwfMimeType ||
178 mime_type == content::kFlashPluginSplMimeType) {
179 return SHOCKWAVE_FLASH;
180 }
181
182 #if defined(ENABLE_PEPPER_CDMS)
183 if (mime_type == kWidevineCdmPluginMimeType)
184 return WIDEVINE_CDM;
185 #endif
186
187 return UNSUPPORTED_MIMETYPE;
188 }
189