Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(101)

Side by Side Diff: chrome/browser/metrics/plugin_metrics_provider.cc

Issue 299783004: Create PluginMetricsProvider class. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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/browser/metrics/plugin_metrics_provider.h"
6
7 #include <string>
8
9 #include "base/prefs/pref_registry_simple.h"
10 #include "base/prefs/pref_service.h"
11 #include "base/prefs/scoped_user_pref_update.h"
12 #include "base/stl_util.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "chrome/browser/browser_process.h"
15 #include "chrome/browser/plugins/plugin_prefs.h"
16 #include "chrome/browser/profiles/profile_manager.h"
17 #include "chrome/common/pref_names.h"
18 #include "components/metrics/proto/system_profile.pb.h"
19 #include "content/public/browser/child_process_data.h"
20 #include "content/public/browser/plugin_service.h"
21 #include "content/public/common/process_type.h"
22 #include "content/public/common/webplugininfo.h"
23
24 namespace {
25
26 // Returns the plugin preferences corresponding for this user, if available.
27 // If multiple user profiles are loaded, returns the preferences corresponding
28 // to an arbitrary one of the profiles.
29 PluginPrefs* GetPluginPrefs() {
30 ProfileManager* profile_manager = g_browser_process->profile_manager();
31
32 if (!profile_manager) {
33 // The profile manager can be NULL when testing.
34 return NULL;
35 }
36
37 std::vector<Profile*> profiles = profile_manager->GetLoadedProfiles();
38 if (profiles.empty())
39 return NULL;
40
41 return PluginPrefs::GetForProfile(profiles.front()).get();
42 }
43
44 // Fills |plugin| with the info contained in |plugin_info| and |plugin_prefs|.
45 void SetPluginInfo(const content::WebPluginInfo& plugin_info,
46 const PluginPrefs* plugin_prefs,
47 metrics::SystemProfileProto::Plugin* plugin) {
48 plugin->set_name(base::UTF16ToUTF8(plugin_info.name));
49 plugin->set_filename(plugin_info.path.BaseName().AsUTF8Unsafe());
50 plugin->set_version(base::UTF16ToUTF8(plugin_info.version));
51 plugin->set_is_pepper(plugin_info.is_pepper_plugin());
52 if (plugin_prefs)
53 plugin->set_is_disabled(!plugin_prefs->IsPluginEnabled(plugin_info));
54 }
55
56 } // namespace
57
58 // This is used to quickly log stats from child process related notifications in
59 // PluginMetricsProvider::child_stats_buffer_. The buffer's contents are
60 // transferred out when Local State is periodically saved. The information is
61 // then reported to the UMA server on next launch.
62 struct PluginMetricsProvider::ChildProcessStats {
63 public:
64 explicit ChildProcessStats(int process_type)
65 : process_launches(0),
66 process_crashes(0),
67 instances(0),
68 loading_errors(0),
69 process_type(process_type) {}
70
71 // This constructor is only used by the map to return some default value for
72 // an index for which no value has been assigned.
73 ChildProcessStats()
74 : process_launches(0),
75 process_crashes(0),
76 instances(0),
77 loading_errors(0),
78 process_type(content::PROCESS_TYPE_UNKNOWN) {}
79
80 // The number of times that the given child process has been launched
81 int process_launches;
82
83 // The number of times that the given child process has crashed
84 int process_crashes;
85
86 // The number of instances of this child process that have been created.
87 // An instance is a DOM object rendered by this child process during a page
88 // load.
89 int instances;
90
91 // The number of times there was an error loading an instance of this child
92 // process.
93 int loading_errors;
94
95 int process_type;
96 };
97
98 PluginMetricsProvider::PluginMetricsProvider(PrefService* local_state)
99 : local_state_(local_state),
100 weak_ptr_factory_(this) {
101 DCHECK(local_state_);
102
103 BrowserChildProcessObserver::Add(this);
104 }
105
106 PluginMetricsProvider::~PluginMetricsProvider() {
107 BrowserChildProcessObserver::Remove(this);
108 }
109
110 void PluginMetricsProvider::GetPluginInformation(
111 const base::Closure& done_callback) {
112 content::PluginService::GetInstance()->GetPlugins(
113 base::Bind(&PluginMetricsProvider::OnGotPlugins,
114 weak_ptr_factory_.GetWeakPtr(),
115 done_callback));
116 }
117
118 void PluginMetricsProvider::ProvideSystemProfileMetrics(
119 metrics::SystemProfileProto* system_profile_proto) {
120 PluginPrefs* plugin_prefs = GetPluginPrefs();
121 for (size_t i = 0; i < plugins_.size(); ++i) {
122 SetPluginInfo(plugins_[i], plugin_prefs,
123 system_profile_proto->add_plugin());
124 }
125 }
126
127 void PluginMetricsProvider::ProvideStabilityMetrics(
128 metrics::SystemProfileProto* system_profile_proto) {
129 const base::ListValue* plugin_stats_list = local_state_->GetList(
130 prefs::kStabilityPluginStats);
131 if (!plugin_stats_list)
132 return;
133
134 metrics::SystemProfileProto::Stability* stability =
135 system_profile_proto->mutable_stability();
136 for (base::ListValue::const_iterator iter = plugin_stats_list->begin();
137 iter != plugin_stats_list->end(); ++iter) {
138 if (!(*iter)->IsType(base::Value::TYPE_DICTIONARY)) {
139 NOTREACHED();
140 continue;
141 }
142 base::DictionaryValue* plugin_dict =
143 static_cast<base::DictionaryValue*>(*iter);
144
145 // Note that this search is potentially a quadratic operation, but given the
146 // low number of plugins installed on a "reasonable" setup, this should be
147 // fine.
148 // TODO(isherman): Verify that this does not show up as a hotspot in
149 // profiler runs.
150 const metrics::SystemProfileProto::Plugin* system_profile_plugin = NULL;
151 std::string plugin_name;
152 plugin_dict->GetString(prefs::kStabilityPluginName, &plugin_name);
153 for (int i = 0; i < system_profile_proto->plugin_size(); ++i) {
154 if (system_profile_proto->plugin(i).name() == plugin_name) {
155 system_profile_plugin = &system_profile_proto->plugin(i);
156 break;
157 }
158 }
159
160 if (!system_profile_plugin) {
161 NOTREACHED();
162 continue;
163 }
164
165 metrics::SystemProfileProto::Stability::PluginStability* plugin_stability =
166 stability->add_plugin_stability();
167 *plugin_stability->mutable_plugin() = *system_profile_plugin;
168
169 int launches = 0;
170 plugin_dict->GetInteger(prefs::kStabilityPluginLaunches, &launches);
171 if (launches > 0)
172 plugin_stability->set_launch_count(launches);
173
174 int instances = 0;
175 plugin_dict->GetInteger(prefs::kStabilityPluginInstances, &instances);
176 if (instances > 0)
177 plugin_stability->set_instance_count(instances);
178
179 int crashes = 0;
180 plugin_dict->GetInteger(prefs::kStabilityPluginCrashes, &crashes);
181 if (crashes > 0)
182 plugin_stability->set_crash_count(crashes);
183
184 int loading_errors = 0;
185 plugin_dict->GetInteger(prefs::kStabilityPluginLoadingErrors,
186 &loading_errors);
187 if (loading_errors > 0)
188 plugin_stability->set_loading_error_count(loading_errors);
189 }
190
191 local_state_->ClearPref(prefs::kStabilityPluginStats);
192 }
193
194 void PluginMetricsProvider::RecordPluginChanges() {
195 ListPrefUpdate update(local_state_, prefs::kStabilityPluginStats);
196 base::ListValue* plugins = update.Get();
197 DCHECK(plugins);
198
199 for (base::ListValue::iterator value_iter = plugins->begin();
200 value_iter != plugins->end(); ++value_iter) {
201 if (!(*value_iter)->IsType(base::Value::TYPE_DICTIONARY)) {
202 NOTREACHED();
203 continue;
204 }
205
206 base::DictionaryValue* plugin_dict =
207 static_cast<base::DictionaryValue*>(*value_iter);
208 std::string plugin_name;
209 plugin_dict->GetString(prefs::kStabilityPluginName, &plugin_name);
210 if (plugin_name.empty()) {
211 NOTREACHED();
212 continue;
213 }
214
215 // TODO(viettrungluu): remove conversions
216 base::string16 name16 = base::UTF8ToUTF16(plugin_name);
217 if (child_process_stats_buffer_.find(name16) ==
218 child_process_stats_buffer_.end()) {
219 continue;
220 }
221
222 ChildProcessStats stats = child_process_stats_buffer_[name16];
223 if (stats.process_launches) {
224 int launches = 0;
225 plugin_dict->GetInteger(prefs::kStabilityPluginLaunches, &launches);
226 launches += stats.process_launches;
227 plugin_dict->SetInteger(prefs::kStabilityPluginLaunches, launches);
228 }
229 if (stats.process_crashes) {
230 int crashes = 0;
231 plugin_dict->GetInteger(prefs::kStabilityPluginCrashes, &crashes);
232 crashes += stats.process_crashes;
233 plugin_dict->SetInteger(prefs::kStabilityPluginCrashes, crashes);
234 }
235 if (stats.instances) {
236 int instances = 0;
237 plugin_dict->GetInteger(prefs::kStabilityPluginInstances, &instances);
238 instances += stats.instances;
239 plugin_dict->SetInteger(prefs::kStabilityPluginInstances, instances);
240 }
241 if (stats.loading_errors) {
242 int loading_errors = 0;
243 plugin_dict->GetInteger(prefs::kStabilityPluginLoadingErrors,
244 &loading_errors);
245 loading_errors += stats.loading_errors;
246 plugin_dict->SetInteger(prefs::kStabilityPluginLoadingErrors,
247 loading_errors);
248 }
249
250 child_process_stats_buffer_.erase(name16);
251 }
252
253 // Now go through and add dictionaries for plugins that didn't already have
254 // reports in Local State.
255 for (std::map<base::string16, ChildProcessStats>::iterator cache_iter =
256 child_process_stats_buffer_.begin();
257 cache_iter != child_process_stats_buffer_.end(); ++cache_iter) {
258 ChildProcessStats stats = cache_iter->second;
259
260 // Insert only plugins information into the plugins list.
261 if (!IsPluginProcess(stats.process_type))
262 continue;
263
264 // TODO(viettrungluu): remove conversion
265 std::string plugin_name = base::UTF16ToUTF8(cache_iter->first);
266
267 base::DictionaryValue* plugin_dict = new base::DictionaryValue;
268
269 plugin_dict->SetString(prefs::kStabilityPluginName, plugin_name);
270 plugin_dict->SetInteger(prefs::kStabilityPluginLaunches,
271 stats.process_launches);
272 plugin_dict->SetInteger(prefs::kStabilityPluginCrashes,
273 stats.process_crashes);
274 plugin_dict->SetInteger(prefs::kStabilityPluginInstances,
275 stats.instances);
276 plugin_dict->SetInteger(prefs::kStabilityPluginLoadingErrors,
277 stats.loading_errors);
278 plugins->Append(plugin_dict);
279 }
280 child_process_stats_buffer_.clear();
281 }
282
283 void PluginMetricsProvider::LogPluginLoadingError(
284 const base::FilePath& plugin_path) {
285 content::WebPluginInfo plugin;
286 bool success =
287 content::PluginService::GetInstance()->GetPluginInfoByPath(plugin_path,
288 &plugin);
289 DCHECK(success);
290 ChildProcessStats& stats = child_process_stats_buffer_[plugin.name];
291 // Initialize the type if this entry is new.
292 if (stats.process_type == content::PROCESS_TYPE_UNKNOWN) {
293 // The plug-in process might not actually be of type PLUGIN (which means
294 // NPAPI), but we only care that it is *a* plug-in process.
295 stats.process_type = content::PROCESS_TYPE_PLUGIN;
296 } else {
297 DCHECK(IsPluginProcess(stats.process_type));
298 }
299 stats.loading_errors++;
300 }
301
302 void PluginMetricsProvider::SetPluginsForTesting(
303 const std::vector<content::WebPluginInfo>& plugins) {
304 plugins_ = plugins;
305 }
306
307 // static
308 bool PluginMetricsProvider::IsPluginProcess(int process_type) {
309 return (process_type == content::PROCESS_TYPE_PLUGIN ||
310 process_type == content::PROCESS_TYPE_PPAPI_PLUGIN ||
311 process_type == content::PROCESS_TYPE_PPAPI_BROKER);
312 }
313
314 // static
315 void PluginMetricsProvider::RegisterPrefs(PrefRegistrySimple* registry) {
316 registry->RegisterListPref(prefs::kStabilityPluginStats);
317 }
318
319 void PluginMetricsProvider::OnGotPlugins(
320 const base::Closure& done_callback,
321 const std::vector<content::WebPluginInfo>& plugins) {
322 plugins_ = plugins;
323 done_callback.Run();
324 }
325
326 PluginMetricsProvider::ChildProcessStats&
327 PluginMetricsProvider::GetChildProcessStats(
328 const content::ChildProcessData& data) {
329 const base::string16& child_name = data.name;
330 if (!ContainsKey(child_process_stats_buffer_, child_name)) {
331 child_process_stats_buffer_[child_name] =
332 ChildProcessStats(data.process_type);
333 }
334 return child_process_stats_buffer_[child_name];
335 }
336
337 void PluginMetricsProvider::BrowserChildProcessHostConnected(
338 const content::ChildProcessData& data) {
339 GetChildProcessStats(data).process_launches++;
340 }
341
342 void PluginMetricsProvider::BrowserChildProcessCrashed(
343 const content::ChildProcessData& data) {
344 GetChildProcessStats(data).process_crashes++;
345 }
346
347 void PluginMetricsProvider::BrowserChildProcessInstanceCreated(
348 const content::ChildProcessData& data) {
349 GetChildProcessStats(data).instances++;
350 }
OLDNEW
« no previous file with comments | « chrome/browser/metrics/plugin_metrics_provider.h ('k') | chrome/browser/metrics/plugin_metrics_provider_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698