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

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 bool IsPluginProcess(int process_type) {
45 return (process_type == content::PROCESS_TYPE_PLUGIN ||
46 process_type == content::PROCESS_TYPE_PPAPI_PLUGIN ||
47 process_type == content::PROCESS_TYPE_PPAPI_BROKER);
48 }
Ilya Sherman 2014/05/22 14:52:20 nit: Might be worth making this a public static me
Alexei Svitkine (slow) 2014/05/22 15:38:54 Done. Removed the equivalent static method from Me
49
50 // Fills |plugin| with the info contained in |plugin_info| and |plugin_prefs|.
51 void SetPluginInfo(const content::WebPluginInfo& plugin_info,
52 const PluginPrefs* plugin_prefs,
53 metrics::SystemProfileProto::Plugin* plugin) {
54 plugin->set_name(base::UTF16ToUTF8(plugin_info.name));
55 plugin->set_filename(plugin_info.path.BaseName().AsUTF8Unsafe());
56 plugin->set_version(base::UTF16ToUTF8(plugin_info.version));
57 plugin->set_is_pepper(plugin_info.is_pepper_plugin());
58 if (plugin_prefs)
59 plugin->set_is_disabled(!plugin_prefs->IsPluginEnabled(plugin_info));
60 }
61
62 } // namespace
63
64 // This is used to quickly log stats from child process related notifications in
65 // PluginMetricsProvider::child_stats_buffer_. The buffer's contents are
66 // transferred out when Local State is periodically saved. The information is
67 // then reported to the UMA server on next launch.
68 struct PluginMetricsProvider::ChildProcessStats {
69 public:
70 explicit ChildProcessStats(int process_type)
71 : process_launches(0),
72 process_crashes(0),
73 instances(0),
74 loading_errors(0),
75 process_type(process_type) {}
76
77 // This constructor is only used by the map to return some default value for
78 // an index for which no value has been assigned.
79 ChildProcessStats()
80 : process_launches(0),
81 process_crashes(0),
82 instances(0),
83 loading_errors(0),
84 process_type(content::PROCESS_TYPE_UNKNOWN) {}
85
86 // The number of times that the given child process has been launched
87 int process_launches;
88
89 // The number of times that the given child process has crashed
90 int process_crashes;
91
92 // The number of instances of this child process that have been created.
93 // An instance is a DOM object rendered by this child process during a page
94 // load.
95 int instances;
96
97 // The number of times there was an error loading an instance of this child
98 // process.
99 int loading_errors;
100
101 int process_type;
102 };
103
104 PluginMetricsProvider::PluginMetricsProvider(PrefService* local_state)
105 : local_state_(local_state),
106 weak_ptr_factory_(this) {
107 DCHECK(local_state_);
108
109 BrowserChildProcessObserver::Add(this);
110 }
111
112 PluginMetricsProvider::~PluginMetricsProvider() {
113 BrowserChildProcessObserver::Remove(this);
114 }
115
116 void PluginMetricsProvider::GetPluginInformation(
117 const base::Closure& done_callback) {
118 content::PluginService::GetInstance()->GetPlugins(
119 base::Bind(&PluginMetricsProvider::OnGotPlugins,
120 weak_ptr_factory_.GetWeakPtr(),
121 done_callback));
122 }
123
124 void PluginMetricsProvider::ProvideSystemProfileMetrics(
125 metrics::SystemProfileProto* system_profile_proto) {
126 PluginPrefs* plugin_prefs = GetPluginPrefs();
127 for (size_t i = 0; i < plugins_.size(); ++i) {
128 SetPluginInfo(plugins_[i], plugin_prefs,
129 system_profile_proto->add_plugin());
130 }
131 }
132
133 void PluginMetricsProvider::ProvideStabilityMetrics(
134 metrics::SystemProfileProto* system_profile_proto) {
135 // Now log plugin stability info.
Ilya Sherman 2014/05/22 14:52:20 nit: Drop this?
Alexei Svitkine (slow) 2014/05/22 15:38:54 Done.
136 const base::ListValue* plugin_stats_list = local_state_->GetList(
137 prefs::kStabilityPluginStats);
138 if (!plugin_stats_list)
139 return;
140
141 metrics::SystemProfileProto::Stability* stability =
142 system_profile_proto->mutable_stability();
143 for (base::ListValue::const_iterator iter = plugin_stats_list->begin();
144 iter != plugin_stats_list->end(); ++iter) {
145 if (!(*iter)->IsType(base::Value::TYPE_DICTIONARY)) {
146 NOTREACHED();
147 continue;
148 }
149 base::DictionaryValue* plugin_dict =
150 static_cast<base::DictionaryValue*>(*iter);
151
152 // Note that this search is potentially a quadratic operation, but given the
153 // low number of plugins installed on a "reasonable" setup, this should be
154 // fine.
155 // TODO(isherman): Verify that this does not show up as a hotspot in
156 // profiler runs.
157 const metrics::SystemProfileProto::Plugin* system_profile_plugin = NULL;
158 std::string plugin_name;
159 plugin_dict->GetString(prefs::kStabilityPluginName, &plugin_name);
160 for (int i = 0; i < system_profile_proto->plugin_size(); ++i) {
161 if (system_profile_proto->plugin(i).name() == plugin_name) {
162 system_profile_plugin = &system_profile_proto->plugin(i);
163 break;
164 }
165 }
166
167 if (!system_profile_plugin) {
168 NOTREACHED();
169 continue;
170 }
171
172 metrics::SystemProfileProto::Stability::PluginStability* plugin_stability =
173 stability->add_plugin_stability();
174 *plugin_stability->mutable_plugin() = *system_profile_plugin;
175
176 int launches = 0;
177 plugin_dict->GetInteger(prefs::kStabilityPluginLaunches, &launches);
178 if (launches > 0)
179 plugin_stability->set_launch_count(launches);
180
181 int instances = 0;
182 plugin_dict->GetInteger(prefs::kStabilityPluginInstances, &instances);
183 if (instances > 0)
184 plugin_stability->set_instance_count(instances);
185
186 int crashes = 0;
187 plugin_dict->GetInteger(prefs::kStabilityPluginCrashes, &crashes);
188 if (crashes > 0)
189 plugin_stability->set_crash_count(crashes);
190
191 int loading_errors = 0;
192 plugin_dict->GetInteger(prefs::kStabilityPluginLoadingErrors,
193 &loading_errors);
194 if (loading_errors > 0)
195 plugin_stability->set_loading_error_count(loading_errors);
196 }
197
198 local_state_->ClearPref(prefs::kStabilityPluginStats);
199 }
200
201 void PluginMetricsProvider::RecordPluginChanges() {
202 ListPrefUpdate update(local_state_, prefs::kStabilityPluginStats);
203 base::ListValue* plugins = update.Get();
204 DCHECK(plugins);
205
206 for (base::ListValue::iterator value_iter = plugins->begin();
207 value_iter != plugins->end(); ++value_iter) {
208 if (!(*value_iter)->IsType(base::Value::TYPE_DICTIONARY)) {
209 NOTREACHED();
210 continue;
211 }
212
213 base::DictionaryValue* plugin_dict =
214 static_cast<base::DictionaryValue*>(*value_iter);
215 std::string plugin_name;
216 plugin_dict->GetString(prefs::kStabilityPluginName, &plugin_name);
217 if (plugin_name.empty()) {
218 NOTREACHED();
219 continue;
220 }
221
222 // TODO(viettrungluu): remove conversions
223 base::string16 name16 = base::UTF8ToUTF16(plugin_name);
224 if (child_process_stats_buffer_.find(name16) ==
225 child_process_stats_buffer_.end()) {
226 continue;
227 }
228
229 ChildProcessStats stats = child_process_stats_buffer_[name16];
230 if (stats.process_launches) {
231 int launches = 0;
232 plugin_dict->GetInteger(prefs::kStabilityPluginLaunches, &launches);
233 launches += stats.process_launches;
234 plugin_dict->SetInteger(prefs::kStabilityPluginLaunches, launches);
235 }
236 if (stats.process_crashes) {
237 int crashes = 0;
238 plugin_dict->GetInteger(prefs::kStabilityPluginCrashes, &crashes);
239 crashes += stats.process_crashes;
240 plugin_dict->SetInteger(prefs::kStabilityPluginCrashes, crashes);
241 }
242 if (stats.instances) {
243 int instances = 0;
244 plugin_dict->GetInteger(prefs::kStabilityPluginInstances, &instances);
245 instances += stats.instances;
246 plugin_dict->SetInteger(prefs::kStabilityPluginInstances, instances);
247 }
248 if (stats.loading_errors) {
249 int loading_errors = 0;
250 plugin_dict->GetInteger(prefs::kStabilityPluginLoadingErrors,
251 &loading_errors);
252 loading_errors += stats.loading_errors;
253 plugin_dict->SetInteger(prefs::kStabilityPluginLoadingErrors,
254 loading_errors);
255 }
256
257 child_process_stats_buffer_.erase(name16);
258 }
259
260 // Now go through and add dictionaries for plugins that didn't already have
261 // reports in Local State.
262 for (std::map<base::string16, ChildProcessStats>::iterator cache_iter =
263 child_process_stats_buffer_.begin();
264 cache_iter != child_process_stats_buffer_.end(); ++cache_iter) {
265 ChildProcessStats stats = cache_iter->second;
266
267 // Insert only plugins information into the plugins list.
268 if (!IsPluginProcess(stats.process_type))
269 continue;
270
271 // TODO(viettrungluu): remove conversion
272 std::string plugin_name = base::UTF16ToUTF8(cache_iter->first);
273
274 base::DictionaryValue* plugin_dict = new base::DictionaryValue;
275
276 plugin_dict->SetString(prefs::kStabilityPluginName, plugin_name);
277 plugin_dict->SetInteger(prefs::kStabilityPluginLaunches,
278 stats.process_launches);
279 plugin_dict->SetInteger(prefs::kStabilityPluginCrashes,
280 stats.process_crashes);
281 plugin_dict->SetInteger(prefs::kStabilityPluginInstances,
282 stats.instances);
283 plugin_dict->SetInteger(prefs::kStabilityPluginLoadingErrors,
284 stats.loading_errors);
285 plugins->Append(plugin_dict);
286 }
287 child_process_stats_buffer_.clear();
288 }
289
290 void PluginMetricsProvider::LogPluginLoadingError(
291 const base::FilePath& plugin_path) {
292 content::WebPluginInfo plugin;
293 bool success =
294 content::PluginService::GetInstance()->GetPluginInfoByPath(plugin_path,
295 &plugin);
296 DCHECK(success);
297 ChildProcessStats& stats = child_process_stats_buffer_[plugin.name];
298 // Initialize the type if this entry is new.
299 if (stats.process_type == content::PROCESS_TYPE_UNKNOWN) {
300 // The plug-in process might not actually of type PLUGIN (which means
Ilya Sherman 2014/05/22 14:52:20 nit: "might not actually of type" -> "might not ac
Alexei Svitkine (slow) 2014/05/22 15:38:54 Done.
301 // NPAPI), but we only care that it is *a* plug-in process.
302 stats.process_type = content::PROCESS_TYPE_PLUGIN;
303 } else {
304 DCHECK(IsPluginProcess(stats.process_type));
305 }
306 stats.loading_errors++;
307 }
308
309 void PluginMetricsProvider::SetPluginsForTesting(
310 const std::vector<content::WebPluginInfo>& plugins) {
311 plugins_ = plugins;
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

Powered by Google App Engine
This is Rietveld 408576698