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