Home | History | Annotate | Download | only in metrics
      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 
     37 MetricsLog::MetricsLog(const std::string& client_id, int session_id)
     38     : MetricsLogBase(client_id, session_id, MetricsLog::GetVersionString()) {}
     39 
     40 MetricsLog::~MetricsLog() {}
     41 
     42 // static
     43 void MetricsLog::RegisterPrefs(PrefService* local_state) {
     44   local_state->RegisterListPref(prefs::kStabilityPluginStats);
     45 }
     46 
     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 
     62 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
     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 
     88 MetricsLog* MetricsLog::AsMetricsLog() {
     89   return this;
     90 }
     91 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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