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