• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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/metrics_log.h"
6 
7 #include <string>
8 #include <vector>
9 
10 #include "base/basictypes.h"
11 #include "base/file_util.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/perftimer.h"
14 #include "base/string_util.h"
15 #include "base/sys_info.h"
16 #include "base/third_party/nspr/prtime.h"
17 #include "base/time.h"
18 #include "base/utf_string_conversions.h"
19 #include "chrome/browser/autocomplete/autocomplete.h"
20 #include "chrome/browser/autocomplete/autocomplete_match.h"
21 #include "chrome/browser/browser_process.h"
22 #include "chrome/browser/gpu_data_manager.h"
23 #include "chrome/browser/prefs/pref_service.h"
24 #include "chrome/common/chrome_version_info.h"
25 #include "chrome/common/logging_chrome.h"
26 #include "chrome/common/pref_names.h"
27 #include "googleurl/src/gurl.h"
28 #include "webkit/plugins/npapi/webplugininfo.h"
29 
30 #define OPEN_ELEMENT_FOR_SCOPE(name) ScopedElement scoped_element(this, name)
31 
32 // http://blogs.msdn.com/oldnewthing/archive/2004/10/25/247180.aspx
33 #if defined(OS_WIN)
34 extern "C" IMAGE_DOS_HEADER __ImageBase;
35 #endif
36 
MetricsLog(const std::string & client_id,int session_id)37 MetricsLog::MetricsLog(const std::string& client_id, int session_id)
38     : MetricsLogBase(client_id, session_id, MetricsLog::GetVersionString()) {}
39 
~MetricsLog()40 MetricsLog::~MetricsLog() {}
41 
42 // static
RegisterPrefs(PrefService * local_state)43 void MetricsLog::RegisterPrefs(PrefService* local_state) {
44   local_state->RegisterListPref(prefs::kStabilityPluginStats);
45 }
46 
GetIncrementalUptime(PrefService * pref)47 int64 MetricsLog::GetIncrementalUptime(PrefService* pref) {
48   base::TimeTicks now = base::TimeTicks::Now();
49   static base::TimeTicks last_updated_time(now);
50   int64 incremental_time = (now - last_updated_time).InSeconds();
51   last_updated_time = now;
52 
53   if (incremental_time > 0) {
54     int64 metrics_uptime = pref->GetInt64(prefs::kUninstallMetricsUptimeSec);
55     metrics_uptime += incremental_time;
56     pref->SetInt64(prefs::kUninstallMetricsUptimeSec, metrics_uptime);
57   }
58 
59   return incremental_time;
60 }
61 
GetInstallDate() const62 std::string MetricsLog::GetInstallDate() const {
63   PrefService* pref = g_browser_process->local_state();
64   if (pref) {
65     return pref->GetString(prefs::kMetricsClientIDTimestamp);
66   } else {
67     NOTREACHED();
68     return "0";
69   }
70 }
71 
72 // static
GetVersionString()73 std::string MetricsLog::GetVersionString() {
74   chrome::VersionInfo version_info;
75   if (!version_info.is_valid()) {
76     NOTREACHED() << "Unable to retrieve version info.";
77     return std::string();
78   }
79 
80   std::string version = version_info.Version();
81   if (!version_extension_.empty())
82     version += version_extension_;
83   if (!version_info.IsOfficialBuild())
84     version.append("-devel");
85   return version;
86 }
87 
AsMetricsLog()88 MetricsLog* MetricsLog::AsMetricsLog() {
89   return this;
90 }
91 
RecordIncrementalStabilityElements()92 void MetricsLog::RecordIncrementalStabilityElements() {
93   DCHECK(!locked_);
94 
95   PrefService* pref = g_browser_process->local_state();
96   DCHECK(pref);
97 
98   OPEN_ELEMENT_FOR_SCOPE("profile");
99   WriteCommonEventAttributes();
100 
101   WriteInstallElement();
102 
103   {
104     OPEN_ELEMENT_FOR_SCOPE("stability");  // Minimal set of stability elements.
105     WriteRequiredStabilityAttributes(pref);
106     WriteRealtimeStabilityAttributes(pref);
107 
108     WritePluginStabilityElements(pref);
109   }
110 }
111 
WriteStabilityElement(PrefService * pref)112 void MetricsLog::WriteStabilityElement(PrefService* pref) {
113   DCHECK(!locked_);
114 
115   DCHECK(pref);
116 
117   // Get stability attributes out of Local State, zeroing out stored values.
118   // NOTE: This could lead to some data loss if this report isn't successfully
119   //       sent, but that's true for all the metrics.
120 
121   OPEN_ELEMENT_FOR_SCOPE("stability");
122   WriteRequiredStabilityAttributes(pref);
123   WriteRealtimeStabilityAttributes(pref);
124 
125   // TODO(jar): The following are all optional, so we *could* optimize them for
126   // values of zero (and not include them).
127   WriteIntAttribute("incompleteshutdowncount",
128                     pref->GetInteger(
129                         prefs::kStabilityIncompleteSessionEndCount));
130   pref->SetInteger(prefs::kStabilityIncompleteSessionEndCount, 0);
131 
132 
133   WriteIntAttribute("breakpadregistrationok",
134       pref->GetInteger(prefs::kStabilityBreakpadRegistrationSuccess));
135   pref->SetInteger(prefs::kStabilityBreakpadRegistrationSuccess, 0);
136   WriteIntAttribute("breakpadregistrationfail",
137       pref->GetInteger(prefs::kStabilityBreakpadRegistrationFail));
138   pref->SetInteger(prefs::kStabilityBreakpadRegistrationFail, 0);
139   WriteIntAttribute("debuggerpresent",
140                    pref->GetInteger(prefs::kStabilityDebuggerPresent));
141   pref->SetInteger(prefs::kStabilityDebuggerPresent, 0);
142   WriteIntAttribute("debuggernotpresent",
143                    pref->GetInteger(prefs::kStabilityDebuggerNotPresent));
144   pref->SetInteger(prefs::kStabilityDebuggerNotPresent, 0);
145 
146   WritePluginStabilityElements(pref);
147 }
148 
WritePluginStabilityElements(PrefService * pref)149 void MetricsLog::WritePluginStabilityElements(PrefService* pref) {
150   // Now log plugin stability info.
151   const ListValue* plugin_stats_list = pref->GetList(
152       prefs::kStabilityPluginStats);
153   if (plugin_stats_list) {
154     OPEN_ELEMENT_FOR_SCOPE("plugins");
155     for (ListValue::const_iterator iter = plugin_stats_list->begin();
156          iter != plugin_stats_list->end(); ++iter) {
157       if (!(*iter)->IsType(Value::TYPE_DICTIONARY)) {
158         NOTREACHED();
159         continue;
160       }
161       DictionaryValue* plugin_dict = static_cast<DictionaryValue*>(*iter);
162 
163       std::string plugin_name;
164       plugin_dict->GetString(prefs::kStabilityPluginName, &plugin_name);
165 
166       OPEN_ELEMENT_FOR_SCOPE("pluginstability");
167       // Use "filename" instead of "name", otherwise we need to update the
168       // UMA servers.
169       WriteAttribute("filename", CreateBase64Hash(plugin_name));
170 
171       int launches = 0;
172       plugin_dict->GetInteger(prefs::kStabilityPluginLaunches, &launches);
173       WriteIntAttribute("launchcount", launches);
174 
175       int instances = 0;
176       plugin_dict->GetInteger(prefs::kStabilityPluginInstances, &instances);
177       WriteIntAttribute("instancecount", instances);
178 
179       int crashes = 0;
180       plugin_dict->GetInteger(prefs::kStabilityPluginCrashes, &crashes);
181       WriteIntAttribute("crashcount", crashes);
182     }
183 
184     pref->ClearPref(prefs::kStabilityPluginStats);
185   }
186 }
187 
WriteRequiredStabilityAttributes(PrefService * pref)188 void MetricsLog::WriteRequiredStabilityAttributes(PrefService* pref) {
189   // The server refuses data that doesn't have certain values.  crashcount and
190   // launchcount are currently "required" in the "stability" group.
191   WriteIntAttribute("launchcount",
192                     pref->GetInteger(prefs::kStabilityLaunchCount));
193   pref->SetInteger(prefs::kStabilityLaunchCount, 0);
194   WriteIntAttribute("crashcount",
195                     pref->GetInteger(prefs::kStabilityCrashCount));
196   pref->SetInteger(prefs::kStabilityCrashCount, 0);
197 }
198 
WriteRealtimeStabilityAttributes(PrefService * pref)199 void MetricsLog::WriteRealtimeStabilityAttributes(PrefService* pref) {
200   // Update the stats which are critical for real-time stability monitoring.
201   // Since these are "optional," only list ones that are non-zero, as the counts
202   // are aggergated (summed) server side.
203 
204   int count = pref->GetInteger(prefs::kStabilityPageLoadCount);
205   if (count) {
206     WriteIntAttribute("pageloadcount", count);
207     pref->SetInteger(prefs::kStabilityPageLoadCount, 0);
208   }
209 
210   count = pref->GetInteger(prefs::kStabilityRendererCrashCount);
211   if (count) {
212     WriteIntAttribute("renderercrashcount", count);
213     pref->SetInteger(prefs::kStabilityRendererCrashCount, 0);
214   }
215 
216   count = pref->GetInteger(prefs::kStabilityExtensionRendererCrashCount);
217   if (count) {
218     WriteIntAttribute("extensionrenderercrashcount", count);
219     pref->SetInteger(prefs::kStabilityExtensionRendererCrashCount, 0);
220   }
221 
222   count = pref->GetInteger(prefs::kStabilityRendererHangCount);
223   if (count) {
224     WriteIntAttribute("rendererhangcount", count);
225     pref->SetInteger(prefs::kStabilityRendererHangCount, 0);
226   }
227 
228   count = pref->GetInteger(prefs::kStabilityChildProcessCrashCount);
229   if (count) {
230     WriteIntAttribute("childprocesscrashcount", count);
231     pref->SetInteger(prefs::kStabilityChildProcessCrashCount, 0);
232   }
233 
234 #if defined(OS_CHROMEOS)
235   count = pref->GetInteger(prefs::kStabilityOtherUserCrashCount);
236   if (count) {
237     // TODO(kmixter): Write attribute once log server supports it
238     // and remove warning log.
239     // WriteIntAttribute("otherusercrashcount", count);
240     LOG(WARNING) << "Not yet able to send otherusercrashcount="
241                  << count;
242     pref->SetInteger(prefs::kStabilityOtherUserCrashCount, 0);
243   }
244 
245   count = pref->GetInteger(prefs::kStabilityKernelCrashCount);
246   if (count) {
247     // TODO(kmixter): Write attribute once log server supports it
248     // and remove warning log.
249     // WriteIntAttribute("kernelcrashcount", count);
250     LOG(WARNING) << "Not yet able to send kernelcrashcount="
251                  << count;
252     pref->SetInteger(prefs::kStabilityKernelCrashCount, 0);
253   }
254 
255   count = pref->GetInteger(prefs::kStabilitySystemUncleanShutdownCount);
256   if (count) {
257     // TODO(kmixter): Write attribute once log server supports it
258     // and remove warning log.
259     // WriteIntAttribute("systemuncleanshutdowns", count);
260     LOG(WARNING) << "Not yet able to send systemuncleanshutdowns="
261                  << count;
262     pref->SetInteger(prefs::kStabilitySystemUncleanShutdownCount, 0);
263   }
264 #endif  // OS_CHROMEOS
265 
266   int64 recent_duration = GetIncrementalUptime(pref);
267   if (recent_duration)
268     WriteInt64Attribute("uptimesec", recent_duration);
269 }
270 
WritePluginList(const std::vector<webkit::npapi::WebPluginInfo> & plugin_list)271 void MetricsLog::WritePluginList(
272     const std::vector<webkit::npapi::WebPluginInfo>& plugin_list) {
273   DCHECK(!locked_);
274 
275   OPEN_ELEMENT_FOR_SCOPE("plugins");
276 
277   for (std::vector<webkit::npapi::WebPluginInfo>::const_iterator iter =
278            plugin_list.begin();
279        iter != plugin_list.end(); ++iter) {
280     OPEN_ELEMENT_FOR_SCOPE("plugin");
281 
282     // Plugin name and filename are hashed for the privacy of those
283     // testing unreleased new extensions.
284     WriteAttribute("name", CreateBase64Hash(UTF16ToUTF8(iter->name)));
285     std::string filename_bytes =
286 #if defined(OS_WIN)
287         UTF16ToUTF8(iter->path.BaseName().value());
288 #else
289         iter->path.BaseName().value();
290 #endif
291     WriteAttribute("filename", CreateBase64Hash(filename_bytes));
292     WriteAttribute("version", UTF16ToUTF8(iter->version));
293   }
294 }
295 
WriteInstallElement()296 void MetricsLog::WriteInstallElement() {
297   OPEN_ELEMENT_FOR_SCOPE("install");
298   WriteAttribute("installdate", GetInstallDate());
299   WriteIntAttribute("buildid", 0);  // We're using appversion instead.
300 }
301 
RecordEnvironment(const std::vector<webkit::npapi::WebPluginInfo> & plugin_list,const DictionaryValue * profile_metrics)302 void MetricsLog::RecordEnvironment(
303          const std::vector<webkit::npapi::WebPluginInfo>& plugin_list,
304          const DictionaryValue* profile_metrics) {
305   DCHECK(!locked_);
306 
307   PrefService* pref = g_browser_process->local_state();
308 
309   OPEN_ELEMENT_FOR_SCOPE("profile");
310   WriteCommonEventAttributes();
311 
312   WriteInstallElement();
313 
314   WritePluginList(plugin_list);
315 
316   WriteStabilityElement(pref);
317 
318   {
319     OPEN_ELEMENT_FOR_SCOPE("cpu");
320     WriteAttribute("arch", base::SysInfo::CPUArchitecture());
321   }
322 
323   {
324     OPEN_ELEMENT_FOR_SCOPE("memory");
325     WriteIntAttribute("mb", base::SysInfo::AmountOfPhysicalMemoryMB());
326 #if defined(OS_WIN)
327     WriteIntAttribute("dllbase", reinterpret_cast<int>(&__ImageBase));
328 #endif
329   }
330 
331   {
332     OPEN_ELEMENT_FOR_SCOPE("os");
333     WriteAttribute("name",
334                    base::SysInfo::OperatingSystemName());
335     WriteAttribute("version",
336                    base::SysInfo::OperatingSystemVersion());
337   }
338 
339   {
340     OPEN_ELEMENT_FOR_SCOPE("gpu");
341     GpuDataManager* gpu_data_manager = GpuDataManager::GetInstance();
342     if (gpu_data_manager) {
343       WriteIntAttribute("vendorid", gpu_data_manager->gpu_info().vendor_id);
344       WriteIntAttribute("deviceid", gpu_data_manager->gpu_info().device_id);
345     }
346   }
347 
348   {
349     OPEN_ELEMENT_FOR_SCOPE("display");
350     int width = 0;
351     int height = 0;
352     base::SysInfo::GetPrimaryDisplayDimensions(&width, &height);
353     WriteIntAttribute("xsize", width);
354     WriteIntAttribute("ysize", height);
355     WriteIntAttribute("screens", base::SysInfo::DisplayCount());
356   }
357 
358   {
359     OPEN_ELEMENT_FOR_SCOPE("bookmarks");
360     int num_bookmarks_on_bookmark_bar =
361         pref->GetInteger(prefs::kNumBookmarksOnBookmarkBar);
362     int num_folders_on_bookmark_bar =
363         pref->GetInteger(prefs::kNumFoldersOnBookmarkBar);
364     int num_bookmarks_in_other_bookmarks_folder =
365         pref->GetInteger(prefs::kNumBookmarksInOtherBookmarkFolder);
366     int num_folders_in_other_bookmarks_folder =
367         pref->GetInteger(prefs::kNumFoldersInOtherBookmarkFolder);
368     {
369       OPEN_ELEMENT_FOR_SCOPE("bookmarklocation");
370       WriteAttribute("name", "full-tree");
371       WriteIntAttribute("foldercount",
372           num_folders_on_bookmark_bar + num_folders_in_other_bookmarks_folder);
373       WriteIntAttribute("itemcount",
374           num_bookmarks_on_bookmark_bar +
375           num_bookmarks_in_other_bookmarks_folder);
376     }
377     {
378       OPEN_ELEMENT_FOR_SCOPE("bookmarklocation");
379       WriteAttribute("name", "toolbar");
380       WriteIntAttribute("foldercount", num_folders_on_bookmark_bar);
381       WriteIntAttribute("itemcount", num_bookmarks_on_bookmark_bar);
382     }
383   }
384 
385   {
386     OPEN_ELEMENT_FOR_SCOPE("keywords");
387     WriteIntAttribute("count", pref->GetInteger(prefs::kNumKeywords));
388   }
389 
390   if (profile_metrics)
391     WriteAllProfilesMetrics(*profile_metrics);
392 }
393 
WriteAllProfilesMetrics(const DictionaryValue & all_profiles_metrics)394 void MetricsLog::WriteAllProfilesMetrics(
395     const DictionaryValue& all_profiles_metrics) {
396   const std::string profile_prefix(prefs::kProfilePrefix);
397   for (DictionaryValue::key_iterator i = all_profiles_metrics.begin_keys();
398        i != all_profiles_metrics.end_keys(); ++i) {
399     const std::string& key_name = *i;
400     if (key_name.compare(0, profile_prefix.size(), profile_prefix) == 0) {
401       DictionaryValue* profile;
402       if (all_profiles_metrics.GetDictionaryWithoutPathExpansion(key_name,
403                                                                  &profile))
404         WriteProfileMetrics(key_name.substr(profile_prefix.size()), *profile);
405     }
406   }
407 }
408 
WriteProfileMetrics(const std::string & profileidhash,const DictionaryValue & profile_metrics)409 void MetricsLog::WriteProfileMetrics(const std::string& profileidhash,
410                                      const DictionaryValue& profile_metrics) {
411   OPEN_ELEMENT_FOR_SCOPE("userprofile");
412   WriteAttribute("profileidhash", profileidhash);
413   for (DictionaryValue::key_iterator i = profile_metrics.begin_keys();
414        i != profile_metrics.end_keys(); ++i) {
415     Value* value;
416     if (profile_metrics.GetWithoutPathExpansion(*i, &value)) {
417       DCHECK(*i != "id");
418       switch (value->GetType()) {
419         case Value::TYPE_STRING: {
420           std::string string_value;
421           if (value->GetAsString(&string_value)) {
422             OPEN_ELEMENT_FOR_SCOPE("profileparam");
423             WriteAttribute("name", *i);
424             WriteAttribute("value", string_value);
425           }
426           break;
427         }
428 
429         case Value::TYPE_BOOLEAN: {
430           bool bool_value;
431           if (value->GetAsBoolean(&bool_value)) {
432             OPEN_ELEMENT_FOR_SCOPE("profileparam");
433             WriteAttribute("name", *i);
434             WriteIntAttribute("value", bool_value ? 1 : 0);
435           }
436           break;
437         }
438 
439         case Value::TYPE_INTEGER: {
440           int int_value;
441           if (value->GetAsInteger(&int_value)) {
442             OPEN_ELEMENT_FOR_SCOPE("profileparam");
443             WriteAttribute("name", *i);
444             WriteIntAttribute("value", int_value);
445           }
446           break;
447         }
448 
449         default:
450           NOTREACHED();
451           break;
452       }
453     }
454   }
455 }
456 
RecordOmniboxOpenedURL(const AutocompleteLog & log)457 void MetricsLog::RecordOmniboxOpenedURL(const AutocompleteLog& log) {
458   DCHECK(!locked_);
459 
460   OPEN_ELEMENT_FOR_SCOPE("uielement");
461   WriteAttribute("action", "autocomplete");
462   WriteAttribute("targetidhash", "");
463   // TODO(kochi): Properly track windows.
464   WriteIntAttribute("window", 0);
465   WriteCommonEventAttributes();
466 
467   {
468     OPEN_ELEMENT_FOR_SCOPE("autocomplete");
469 
470     WriteIntAttribute("typedlength", static_cast<int>(log.text.length()));
471     WriteIntAttribute("selectedindex", static_cast<int>(log.selected_index));
472     WriteIntAttribute("completedlength",
473                       static_cast<int>(log.inline_autocompleted_length));
474     const std::string input_type(
475         AutocompleteInput::TypeToString(log.input_type));
476     if (!input_type.empty())
477       WriteAttribute("inputtype", input_type);
478 
479     for (AutocompleteResult::const_iterator i(log.result.begin());
480          i != log.result.end(); ++i) {
481       OPEN_ELEMENT_FOR_SCOPE("autocompleteitem");
482       if (i->provider)
483         WriteAttribute("provider", i->provider->name());
484       const std::string result_type(AutocompleteMatch::TypeToString(i->type));
485       if (!result_type.empty())
486         WriteAttribute("resulttype", result_type);
487       WriteIntAttribute("relevance", i->relevance);
488       WriteIntAttribute("isstarred", i->starred ? 1 : 0);
489     }
490   }
491 
492   ++num_events_;
493 }
494