Home | History | Annotate | Download | only in pepper
      1 // Copyright 2014 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/pepper/pepper_uma_host.h"
      6 
      7 #include "base/metrics/histogram.h"
      8 #include "base/sha1.h"
      9 #include "base/strings/string_number_conversions.h"
     10 #include "chrome/common/chrome_switches.h"
     11 #include "chrome/common/render_messages.h"
     12 #include "chrome/renderer/chrome_content_renderer_client.h"
     13 #include "content/public/renderer/pepper_plugin_instance.h"
     14 #include "content/public/renderer/render_thread.h"
     15 #include "content/public/renderer/renderer_ppapi_host.h"
     16 #include "extensions/common/constants.h"
     17 #include "extensions/common/extension.h"
     18 #include "ppapi/c/pp_errors.h"
     19 #include "ppapi/host/dispatch_host_message.h"
     20 #include "ppapi/host/host_message_context.h"
     21 #include "ppapi/host/ppapi_host.h"
     22 #include "ppapi/proxy/ppapi_messages.h"
     23 
     24 #include "widevine_cdm_version.h"  // In SHARED_INTERMEDIATE_DIR.
     25 
     26 namespace {
     27 
     28 const char* const kPredefinedAllowedUMAOrigins[] = {
     29     "6EAED1924DB611B6EEF2A664BD077BE7EAD33B8F",  // see http://crbug.com/317833
     30     "4EB74897CB187C7633357C2FE832E0AD6A44883A"   // see http://crbug.com/317833
     31 };
     32 
     33 const char* const kWhitelistedHistogramPrefixes[] = {
     34     "22F67DA2061FFC4DC9A4974036348D9C38C22919"  // see http://crbug.com/390221
     35 };
     36 
     37 const char* const kWhitelistedPluginBaseNames[] = {
     38 #if defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS)
     39     kWidevineCdmAdapterFileName,  // see http://crbug.com/368743
     40                                   // and http://crbug.com/410630
     41 #endif
     42     "libpdf.so"                   // see http://crbug.com/405305
     43 };
     44 
     45 std::string HashPrefix(const std::string& histogram) {
     46   const std::string id_hash =
     47       base::SHA1HashString(histogram.substr(0, histogram.find('.')));
     48   DCHECK_EQ(id_hash.length(), base::kSHA1Length);
     49   return base::HexEncode(id_hash.c_str(), id_hash.length());
     50 }
     51 
     52 }  // namespace
     53 
     54 PepperUMAHost::PepperUMAHost(content::RendererPpapiHost* host,
     55                              PP_Instance instance,
     56                              PP_Resource resource)
     57     : ResourceHost(host->GetPpapiHost(), instance, resource),
     58       document_url_(host->GetDocumentURL(instance)),
     59       is_plugin_in_process_(host->IsRunningInProcess()) {
     60   if (host->GetPluginInstance(instance)) {
     61     plugin_base_name_ =
     62         host->GetPluginInstance(instance)->GetModulePath().BaseName();
     63   }
     64 
     65   for (size_t i = 0; i < arraysize(kPredefinedAllowedUMAOrigins); ++i)
     66     allowed_origins_.insert(kPredefinedAllowedUMAOrigins[i]);
     67   for (size_t i = 0; i < arraysize(kWhitelistedHistogramPrefixes); ++i)
     68     allowed_histogram_prefixes_.insert(kWhitelistedHistogramPrefixes[i]);
     69   for (size_t i = 0; i < arraysize(kWhitelistedPluginBaseNames); ++i)
     70     allowed_plugin_base_names_.insert(kWhitelistedPluginBaseNames[i]);
     71 }
     72 
     73 PepperUMAHost::~PepperUMAHost() {}
     74 
     75 int32_t PepperUMAHost::OnResourceMessageReceived(
     76     const IPC::Message& msg,
     77     ppapi::host::HostMessageContext* context) {
     78   PPAPI_BEGIN_MESSAGE_MAP(PepperUMAHost, msg)
     79     PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_UMA_HistogramCustomTimes,
     80                                       OnHistogramCustomTimes)
     81     PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_UMA_HistogramCustomCounts,
     82                                       OnHistogramCustomCounts)
     83     PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_UMA_HistogramEnumeration,
     84                                       OnHistogramEnumeration)
     85     PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
     86         PpapiHostMsg_UMA_IsCrashReportingEnabled, OnIsCrashReportingEnabled)
     87   PPAPI_END_MESSAGE_MAP()
     88   return PP_ERROR_FAILED;
     89 }
     90 
     91 bool PepperUMAHost::IsPluginWhitelisted() {
     92 #if defined(ENABLE_EXTENSIONS)
     93   return ChromeContentRendererClient::IsExtensionOrSharedModuleWhitelisted(
     94       document_url_, allowed_origins_);
     95 #else
     96   return false;
     97 #endif
     98 }
     99 
    100 bool PepperUMAHost::IsHistogramAllowed(const std::string& histogram) {
    101   if (is_plugin_in_process_ && histogram.find("NaCl.") == 0) {
    102     return true;
    103   }
    104 
    105   if (IsPluginWhitelisted() &&
    106       allowed_histogram_prefixes_.find(HashPrefix(histogram)) !=
    107           allowed_histogram_prefixes_.end()) {
    108     return true;
    109   }
    110 
    111   if (allowed_plugin_base_names_.find(plugin_base_name_.MaybeAsASCII()) !=
    112       allowed_plugin_base_names_.end()) {
    113     return true;
    114   }
    115 
    116   LOG(ERROR) << "Host or histogram name is not allowed to use the UMA API.";
    117   return false;
    118 }
    119 
    120 #define RETURN_IF_BAD_ARGS(_min, _max, _buckets) \
    121   do {                                           \
    122     if (_min >= _max || _buckets <= 1)           \
    123       return PP_ERROR_BADARGUMENT;               \
    124   } while (0)
    125 
    126 int32_t PepperUMAHost::OnHistogramCustomTimes(
    127     ppapi::host::HostMessageContext* context,
    128     const std::string& name,
    129     int64_t sample,
    130     int64_t min,
    131     int64_t max,
    132     uint32_t bucket_count) {
    133   if (!IsHistogramAllowed(name)) {
    134     return PP_ERROR_NOACCESS;
    135   }
    136   RETURN_IF_BAD_ARGS(min, max, bucket_count);
    137 
    138   base::HistogramBase* counter = base::Histogram::FactoryTimeGet(
    139       name,
    140       base::TimeDelta::FromMilliseconds(min),
    141       base::TimeDelta::FromMilliseconds(max),
    142       bucket_count,
    143       base::HistogramBase::kUmaTargetedHistogramFlag);
    144   // The histogram can be NULL if it is constructed with bad arguments.  Ignore
    145   // that data for this API.  An error message will be logged.
    146   if (counter)
    147     counter->AddTime(base::TimeDelta::FromMilliseconds(sample));
    148   return PP_OK;
    149 }
    150 
    151 int32_t PepperUMAHost::OnHistogramCustomCounts(
    152     ppapi::host::HostMessageContext* context,
    153     const std::string& name,
    154     int32_t sample,
    155     int32_t min,
    156     int32_t max,
    157     uint32_t bucket_count) {
    158   if (!IsHistogramAllowed(name)) {
    159     return PP_ERROR_NOACCESS;
    160   }
    161   RETURN_IF_BAD_ARGS(min, max, bucket_count);
    162 
    163   base::HistogramBase* counter = base::Histogram::FactoryGet(
    164       name,
    165       min,
    166       max,
    167       bucket_count,
    168       base::HistogramBase::kUmaTargetedHistogramFlag);
    169   // The histogram can be NULL if it is constructed with bad arguments.  Ignore
    170   // that data for this API.  An error message will be logged.
    171   if (counter)
    172     counter->Add(sample);
    173   return PP_OK;
    174 }
    175 
    176 int32_t PepperUMAHost::OnHistogramEnumeration(
    177     ppapi::host::HostMessageContext* context,
    178     const std::string& name,
    179     int32_t sample,
    180     int32_t boundary_value) {
    181   if (!IsHistogramAllowed(name)) {
    182     return PP_ERROR_NOACCESS;
    183   }
    184   RETURN_IF_BAD_ARGS(0, boundary_value, boundary_value + 1);
    185 
    186   base::HistogramBase* counter = base::LinearHistogram::FactoryGet(
    187       name,
    188       1,
    189       boundary_value,
    190       boundary_value + 1,
    191       base::HistogramBase::kUmaTargetedHistogramFlag);
    192   // The histogram can be NULL if it is constructed with bad arguments.  Ignore
    193   // that data for this API.  An error message will be logged.
    194   if (counter)
    195     counter->Add(sample);
    196   return PP_OK;
    197 }
    198 
    199 int32_t PepperUMAHost::OnIsCrashReportingEnabled(
    200     ppapi::host::HostMessageContext* context) {
    201   if (!IsPluginWhitelisted())
    202     return PP_ERROR_NOACCESS;
    203   bool enabled = false;
    204   content::RenderThread::Get()->Send(
    205       new ChromeViewHostMsg_IsCrashReportingEnabled(&enabled));
    206   if (enabled)
    207     return PP_OK;
    208   return PP_ERROR_FAILED;
    209 }
    210