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