// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/renderer/plugins/plugin_uma.h"
#include <algorithm>
#include <cstring>
#include "base/metrics/histogram.h"
#include "base/strings/string_util.h"
#include "content/public/common/content_constants.h"
#include "third_party/widevine/cdm/widevine_cdm_common.h"
namespace {
// String we will use to convert mime type to plugin type.
const char kWindowsMediaPlayerType[] = "application/x-mplayer2";
const char kSilverlightTypePrefix[] = "application/x-silverlight";
const char kRealPlayerTypePrefix[] = "audio/x-pn-realaudio";
const char kJavaTypeSubstring[] = "application/x-java-applet";
const char kQuickTimeType[] = "video/quicktime";
// Arrays containing file extensions connected with specific plugins.
// Note: THE ARRAYS MUST BE SORTED BECAUSE BINARY SEARCH IS USED ON THEM!
const char* kWindowsMediaPlayerExtensions[] = {".asx"};
const char* kRealPlayerExtensions[] = {".ra", ".ram", ".rm",
".rmm", ".rmp", ".rpm"};
const char* kQuickTimeExtensions[] = {".moov", ".mov", ".qif",
".qt", ".qti", ".qtif"};
const char* kShockwaveFlashExtensions[] = {".spl", ".swf"};
} // namespace.
class UMASenderImpl : public PluginUMAReporter::UMASender {
virtual void SendPluginUMA(
PluginUMAReporter::ReportType report_type,
PluginUMAReporter::PluginType plugin_type) OVERRIDE;
};
void UMASenderImpl::SendPluginUMA(PluginUMAReporter::ReportType report_type,
PluginUMAReporter::PluginType plugin_type) {
// UMA_HISTOGRAM_ENUMERATION requires constant histogram name. Use string
// constants explicitly instead of trying to use variables for names.
switch (report_type) {
case PluginUMAReporter::MISSING_PLUGIN:
UMA_HISTOGRAM_ENUMERATION("Plugin.MissingPlugins",
plugin_type,
PluginUMAReporter::PLUGIN_TYPE_MAX);
break;
case PluginUMAReporter::DISABLED_PLUGIN:
UMA_HISTOGRAM_ENUMERATION("Plugin.DisabledPlugins",
plugin_type,
PluginUMAReporter::PLUGIN_TYPE_MAX);
break;
default:
NOTREACHED();
}
}
// static.
PluginUMAReporter* PluginUMAReporter::GetInstance() {
return Singleton<PluginUMAReporter>::get();
}
void PluginUMAReporter::ReportPluginMissing(const std::string& plugin_mime_type,
const GURL& plugin_src) {
report_sender_->SendPluginUMA(MISSING_PLUGIN,
GetPluginType(plugin_mime_type, plugin_src));
}
void PluginUMAReporter::ReportPluginDisabled(
const std::string& plugin_mime_type,
const GURL& plugin_src) {
report_sender_->SendPluginUMA(DISABLED_PLUGIN,
GetPluginType(plugin_mime_type, plugin_src));
}
PluginUMAReporter::PluginUMAReporter() : report_sender_(new UMASenderImpl()) {}
PluginUMAReporter::~PluginUMAReporter() {}
// static.
bool PluginUMAReporter::CompareCStrings(const char* first, const char* second) {
return strcmp(first, second) < 0;
}
bool PluginUMAReporter::CStringArrayContainsCString(const char** array,
size_t array_size,
const char* str) {
return std::binary_search(array, array + array_size, str, CompareCStrings);
}
void PluginUMAReporter::ExtractFileExtension(const GURL& src,
std::string* extension) {
std::string extension_file_path(src.ExtractFileName());
if (extension_file_path.empty())
extension_file_path = src.host();
size_t last_dot = extension_file_path.find_last_of('.');
if (last_dot != std::string::npos) {
*extension = extension_file_path.substr(last_dot);
} else {
extension->clear();
}
StringToLowerASCII(extension);
}
PluginUMAReporter::PluginType PluginUMAReporter::GetPluginType(
const std::string& plugin_mime_type,
const GURL& plugin_src) {
// If we know plugin's mime type, we use it to determine plugin's type. Else,
// we try to determine plugin type using plugin source's extension.
if (!plugin_mime_type.empty())
return MimeTypeToPluginType(StringToLowerASCII(plugin_mime_type));
return SrcToPluginType(plugin_src);
}
PluginUMAReporter::PluginType PluginUMAReporter::SrcToPluginType(
const GURL& src) {
std::string file_extension;
ExtractFileExtension(src, &file_extension);
if (CStringArrayContainsCString(kWindowsMediaPlayerExtensions,
arraysize(kWindowsMediaPlayerExtensions),
file_extension.c_str())) {
return WINDOWS_MEDIA_PLAYER;
}
if (CStringArrayContainsCString(kQuickTimeExtensions,
arraysize(kQuickTimeExtensions),
file_extension.c_str())) {
return QUICKTIME;
}
if (CStringArrayContainsCString(kRealPlayerExtensions,
arraysize(kRealPlayerExtensions),
file_extension.c_str())) {
return REALPLAYER;
}
if (CStringArrayContainsCString(kShockwaveFlashExtensions,
arraysize(kShockwaveFlashExtensions),
file_extension.c_str())) {
return SHOCKWAVE_FLASH;
}
return UNSUPPORTED_EXTENSION;
}
PluginUMAReporter::PluginType PluginUMAReporter::MimeTypeToPluginType(
const std::string& mime_type) {
if (mime_type == kWindowsMediaPlayerType)
return WINDOWS_MEDIA_PLAYER;
size_t prefix_length = strlen(kSilverlightTypePrefix);
if (strncmp(mime_type.c_str(), kSilverlightTypePrefix, prefix_length) == 0)
return SILVERLIGHT;
prefix_length = strlen(kRealPlayerTypePrefix);
if (strncmp(mime_type.c_str(), kRealPlayerTypePrefix, prefix_length) == 0)
return REALPLAYER;
if (strstr(mime_type.c_str(), kJavaTypeSubstring))
return JAVA;
if (mime_type == kQuickTimeType)
return QUICKTIME;
if (mime_type == content::kBrowserPluginMimeType)
return BROWSER_PLUGIN;
if (mime_type == content::kFlashPluginSwfMimeType ||
mime_type == content::kFlashPluginSplMimeType) {
return SHOCKWAVE_FLASH;
}
#if defined(ENABLE_PEPPER_CDMS)
if (mime_type == kWidevineCdmPluginMimeType)
return WIDEVINE_CDM;
#endif
return UNSUPPORTED_MIMETYPE;
}