Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / metrics / metrics_log.cc
1 // Copyright (c) 2012 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 <algorithm>
8 #include <string>
9 #include <vector>
10
11 #include "base/base64.h"
12 #include "base/basictypes.h"
13 #include "base/bind.h"
14 #include "base/cpu.h"
15 #include "base/lazy_instance.h"
16 #include "base/memory/scoped_ptr.h"
17 #include "base/prefs/pref_registry_simple.h"
18 #include "base/prefs/pref_service.h"
19 #include "base/profiler/alternate_timer.h"
20 #include "base/sha1.h"
21 #include "base/strings/string_number_conversions.h"
22 #include "base/strings/string_util.h"
23 #include "base/strings/utf_string_conversions.h"
24 #include "base/sys_info.h"
25 #include "base/third_party/nspr/prtime.h"
26 #include "base/time/time.h"
27 #include "base/tracked_objects.h"
28 #include "chrome/browser/autocomplete/autocomplete_input.h"
29 #include "chrome/browser/autocomplete/autocomplete_match.h"
30 #include "chrome/browser/autocomplete/autocomplete_provider.h"
31 #include "chrome/browser/autocomplete/autocomplete_result.h"
32 #include "chrome/browser/browser_process.h"
33 #include "chrome/browser/google/google_util.h"
34 #include "chrome/browser/metrics/extension_metrics.h"
35 #include "chrome/browser/omnibox/omnibox_log.h"
36 #include "chrome/browser/plugins/plugin_prefs.h"
37 #include "chrome/browser/profiles/profile_manager.h"
38 #include "chrome/common/chrome_version_info.h"
39 #include "chrome/common/logging_chrome.h"
40 #include "chrome/common/metrics/variations/variations_util.h"
41 #include "chrome/common/pref_names.h"
42 #include "chrome/installer/util/google_update_settings.h"
43 #include "components/metrics/proto/omnibox_event.pb.h"
44 #include "components/metrics/proto/profiler_event.pb.h"
45 #include "components/metrics/proto/system_profile.pb.h"
46 #include "components/nacl/common/nacl_process_type.h"
47 #include "content/public/browser/gpu_data_manager.h"
48 #include "content/public/common/content_client.h"
49 #include "content/public/common/webplugininfo.h"
50 #include "gpu/config/gpu_info.h"
51 #include "ui/gfx/screen.h"
52 #include "url/gurl.h"
53
54 #if defined(OS_ANDROID)
55 #include "base/android/build_info.h"
56 #endif
57
58 #if defined(OS_WIN)
59 #include "base/win/metro.h"
60
61 // http://blogs.msdn.com/oldnewthing/archive/2004/10/25/247180.aspx
62 extern "C" IMAGE_DOS_HEADER __ImageBase;
63 #endif
64
65 #if defined(OS_CHROMEOS)
66 #include "chrome/browser/metrics/metrics_log_chromeos.h"
67 #endif  // OS_CHROMEOS
68
69 using content::GpuDataManager;
70 using metrics::MetricsLogBase;
71 using metrics::OmniboxEventProto;
72 using metrics::ProfilerEventProto;
73 using metrics::SystemProfileProto;
74 using tracked_objects::ProcessDataSnapshot;
75 typedef chrome_variations::ActiveGroupId ActiveGroupId;
76 typedef SystemProfileProto::GoogleUpdate::ProductInfo ProductInfo;
77
78 namespace {
79
80 // Returns the date at which the current metrics client ID was created as
81 // a string containing seconds since the epoch, or "0" if none was found.
82 std::string GetMetricsEnabledDate(PrefService* pref) {
83   if (!pref) {
84     NOTREACHED();
85     return "0";
86   }
87
88   return pref->GetString(prefs::kMetricsReportingEnabledTimestamp);
89 }
90
91 OmniboxEventProto::InputType AsOmniboxEventInputType(
92     AutocompleteInput::Type type) {
93   switch (type) {
94     case AutocompleteInput::INVALID:
95       return OmniboxEventProto::INVALID;
96     case AutocompleteInput::UNKNOWN:
97       return OmniboxEventProto::UNKNOWN;
98     case AutocompleteInput::URL:
99       return OmniboxEventProto::URL;
100     case AutocompleteInput::QUERY:
101       return OmniboxEventProto::QUERY;
102     case AutocompleteInput::FORCED_QUERY:
103       return OmniboxEventProto::FORCED_QUERY;
104     default:
105       NOTREACHED();
106       return OmniboxEventProto::INVALID;
107   }
108 }
109
110 OmniboxEventProto::Suggestion::ResultType AsOmniboxEventResultType(
111     AutocompleteMatch::Type type) {
112   switch (type) {
113     case AutocompleteMatchType::URL_WHAT_YOU_TYPED:
114       return OmniboxEventProto::Suggestion::URL_WHAT_YOU_TYPED;
115     case AutocompleteMatchType::HISTORY_URL:
116       return OmniboxEventProto::Suggestion::HISTORY_URL;
117     case AutocompleteMatchType::HISTORY_TITLE:
118       return OmniboxEventProto::Suggestion::HISTORY_TITLE;
119     case AutocompleteMatchType::HISTORY_BODY:
120       return OmniboxEventProto::Suggestion::HISTORY_BODY;
121     case AutocompleteMatchType::HISTORY_KEYWORD:
122       return OmniboxEventProto::Suggestion::HISTORY_KEYWORD;
123     case AutocompleteMatchType::NAVSUGGEST:
124       return OmniboxEventProto::Suggestion::NAVSUGGEST;
125     case AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED:
126       return OmniboxEventProto::Suggestion::SEARCH_WHAT_YOU_TYPED;
127     case AutocompleteMatchType::SEARCH_HISTORY:
128       return OmniboxEventProto::Suggestion::SEARCH_HISTORY;
129     case AutocompleteMatchType::SEARCH_SUGGEST:
130       return OmniboxEventProto::Suggestion::SEARCH_SUGGEST;
131     case AutocompleteMatchType::SEARCH_SUGGEST_ENTITY:
132       return OmniboxEventProto::Suggestion::SEARCH_SUGGEST_ENTITY;
133     case AutocompleteMatchType::SEARCH_SUGGEST_INFINITE:
134       return OmniboxEventProto::Suggestion::SEARCH_SUGGEST_INFINITE;
135     case AutocompleteMatchType::SEARCH_SUGGEST_PERSONALIZED:
136       return OmniboxEventProto::Suggestion::SEARCH_SUGGEST_PERSONALIZED;
137     case AutocompleteMatchType::SEARCH_SUGGEST_PROFILE:
138       return OmniboxEventProto::Suggestion::SEARCH_SUGGEST_PROFILE;
139     case AutocompleteMatchType::SEARCH_OTHER_ENGINE:
140       return OmniboxEventProto::Suggestion::SEARCH_OTHER_ENGINE;
141     case AutocompleteMatchType::EXTENSION_APP:
142       return OmniboxEventProto::Suggestion::EXTENSION_APP;
143     case AutocompleteMatchType::BOOKMARK_TITLE:
144       return OmniboxEventProto::Suggestion::BOOKMARK_TITLE;
145     case AutocompleteMatchType::NAVSUGGEST_PERSONALIZED:
146       return OmniboxEventProto::Suggestion::NAVSUGGEST_PERSONALIZED;
147     default:
148       NOTREACHED();
149       return OmniboxEventProto::Suggestion::UNKNOWN_RESULT_TYPE;
150   }
151 }
152
153 OmniboxEventProto::PageClassification AsOmniboxEventPageClassification(
154     AutocompleteInput::PageClassification page_classification) {
155   switch (page_classification) {
156     case AutocompleteInput::INVALID_SPEC:
157       return OmniboxEventProto::INVALID_SPEC;
158     case AutocompleteInput::NTP:
159       return OmniboxEventProto::NTP;
160     case AutocompleteInput::BLANK:
161       return OmniboxEventProto::BLANK;
162     case AutocompleteInput::HOME_PAGE:
163       return OmniboxEventProto::HOME_PAGE;
164     case AutocompleteInput::OTHER:
165       return OmniboxEventProto::OTHER;
166     case AutocompleteInput::SEARCH_RESULT_PAGE_DOING_SEARCH_TERM_REPLACEMENT:
167       return OmniboxEventProto::
168           SEARCH_RESULT_PAGE_DOING_SEARCH_TERM_REPLACEMENT;
169     case AutocompleteInput::INSTANT_NTP_WITH_OMNIBOX_AS_STARTING_FOCUS:
170       return OmniboxEventProto::INSTANT_NTP_WITH_OMNIBOX_AS_STARTING_FOCUS;
171     case AutocompleteInput::INSTANT_NTP_WITH_FAKEBOX_AS_STARTING_FOCUS:
172       return OmniboxEventProto::INSTANT_NTP_WITH_FAKEBOX_AS_STARTING_FOCUS;
173     case AutocompleteInput::SEARCH_RESULT_PAGE_NO_SEARCH_TERM_REPLACEMENT:
174       return OmniboxEventProto::
175           SEARCH_RESULT_PAGE_NO_SEARCH_TERM_REPLACEMENT;
176   }
177   return OmniboxEventProto::INVALID_SPEC;
178 }
179
180 ProfilerEventProto::TrackedObject::ProcessType AsProtobufProcessType(
181     int process_type) {
182   switch (process_type) {
183     case content::PROCESS_TYPE_BROWSER:
184       return ProfilerEventProto::TrackedObject::BROWSER;
185     case content::PROCESS_TYPE_RENDERER:
186       return ProfilerEventProto::TrackedObject::RENDERER;
187     case content::PROCESS_TYPE_PLUGIN:
188       return ProfilerEventProto::TrackedObject::PLUGIN;
189     case content::PROCESS_TYPE_WORKER:
190       return ProfilerEventProto::TrackedObject::WORKER;
191     case content::PROCESS_TYPE_UTILITY:
192       return ProfilerEventProto::TrackedObject::UTILITY;
193     case content::PROCESS_TYPE_ZYGOTE:
194       return ProfilerEventProto::TrackedObject::ZYGOTE;
195     case content::PROCESS_TYPE_SANDBOX_HELPER:
196       return ProfilerEventProto::TrackedObject::SANDBOX_HELPER;
197     case content::PROCESS_TYPE_GPU:
198       return ProfilerEventProto::TrackedObject::GPU;
199     case content::PROCESS_TYPE_PPAPI_PLUGIN:
200       return ProfilerEventProto::TrackedObject::PPAPI_PLUGIN;
201     case content::PROCESS_TYPE_PPAPI_BROKER:
202       return ProfilerEventProto::TrackedObject::PPAPI_BROKER;
203     case PROCESS_TYPE_NACL_LOADER:
204       return ProfilerEventProto::TrackedObject::NACL_LOADER;
205     case PROCESS_TYPE_NACL_BROKER:
206       return ProfilerEventProto::TrackedObject::NACL_BROKER;
207     default:
208       NOTREACHED();
209       return ProfilerEventProto::TrackedObject::UNKNOWN;
210   }
211 }
212
213 SystemProfileProto::Channel AsProtobufChannel(
214     chrome::VersionInfo::Channel channel) {
215   switch (channel) {
216     case chrome::VersionInfo::CHANNEL_UNKNOWN:
217       return SystemProfileProto::CHANNEL_UNKNOWN;
218     case chrome::VersionInfo::CHANNEL_CANARY:
219       return SystemProfileProto::CHANNEL_CANARY;
220     case chrome::VersionInfo::CHANNEL_DEV:
221       return SystemProfileProto::CHANNEL_DEV;
222     case chrome::VersionInfo::CHANNEL_BETA:
223       return SystemProfileProto::CHANNEL_BETA;
224     case chrome::VersionInfo::CHANNEL_STABLE:
225       return SystemProfileProto::CHANNEL_STABLE;
226     default:
227       NOTREACHED();
228       return SystemProfileProto::CHANNEL_UNKNOWN;
229   }
230 }
231
232 // Computes a SHA-1 hash of |data| and returns it as a hex string.
233 std::string ComputeSHA1(const std::string& data) {
234   const std::string sha1 = base::SHA1HashString(data);
235   return base::HexEncode(sha1.data(), sha1.size());
236 }
237
238 #if defined(ENABLE_PLUGINS)
239 // Returns the plugin preferences corresponding for this user, if available.
240 // If multiple user profiles are loaded, returns the preferences corresponding
241 // to an arbitrary one of the profiles.
242 PluginPrefs* GetPluginPrefs() {
243   ProfileManager* profile_manager = g_browser_process->profile_manager();
244
245   if (!profile_manager) {
246     // The profile manager can be NULL when testing.
247     return NULL;
248   }
249
250   std::vector<Profile*> profiles = profile_manager->GetLoadedProfiles();
251   if (profiles.empty())
252     return NULL;
253
254   return PluginPrefs::GetForProfile(profiles.front()).get();
255 }
256
257 // Fills |plugin| with the info contained in |plugin_info| and |plugin_prefs|.
258 void SetPluginInfo(const content::WebPluginInfo& plugin_info,
259                    const PluginPrefs* plugin_prefs,
260                    SystemProfileProto::Plugin* plugin) {
261   plugin->set_name(base::UTF16ToUTF8(plugin_info.name));
262   plugin->set_filename(plugin_info.path.BaseName().AsUTF8Unsafe());
263   plugin->set_version(base::UTF16ToUTF8(plugin_info.version));
264   plugin->set_is_pepper(plugin_info.is_pepper_plugin());
265   if (plugin_prefs)
266     plugin->set_is_disabled(!plugin_prefs->IsPluginEnabled(plugin_info));
267 }
268 #endif  // defined(ENABLE_PLUGINS)
269
270 void WriteFieldTrials(const std::vector<ActiveGroupId>& field_trial_ids,
271                       SystemProfileProto* system_profile) {
272   for (std::vector<ActiveGroupId>::const_iterator it =
273        field_trial_ids.begin(); it != field_trial_ids.end(); ++it) {
274     SystemProfileProto::FieldTrial* field_trial =
275         system_profile->add_field_trial();
276     field_trial->set_name_id(it->name);
277     field_trial->set_group_id(it->group);
278   }
279 }
280
281 // Maps a thread name by replacing trailing sequence of digits with "*".
282 // Examples:
283 // 1. "BrowserBlockingWorker1/23857" => "BrowserBlockingWorker1/*"
284 // 2. "Chrome_IOThread" => "Chrome_IOThread"
285 std::string MapThreadName(const std::string& thread_name) {
286   size_t i = thread_name.length();
287
288   while (i > 0 && isdigit(thread_name[i - 1])) {
289     --i;
290   }
291
292   if (i == thread_name.length())
293     return thread_name;
294
295   return thread_name.substr(0, i) + '*';
296 }
297
298 // Normalizes a source filename (which is platform- and build-method-dependent)
299 // by extracting the last component of the full file name.
300 // Example: "c:\b\build\slave\win\build\src\chrome\app\chrome_main.cc" =>
301 // "chrome_main.cc".
302 std::string NormalizeFileName(const std::string& file_name) {
303   const size_t offset = file_name.find_last_of("\\/");
304   return offset != std::string::npos ? file_name.substr(offset + 1) : file_name;
305 }
306
307 void WriteProfilerData(const ProcessDataSnapshot& profiler_data,
308                        int process_type,
309                        ProfilerEventProto* performance_profile) {
310   for (std::vector<tracked_objects::TaskSnapshot>::const_iterator it =
311            profiler_data.tasks.begin();
312        it != profiler_data.tasks.end(); ++it) {
313     const tracked_objects::DeathDataSnapshot& death_data = it->death_data;
314     ProfilerEventProto::TrackedObject* tracked_object =
315         performance_profile->add_tracked_object();
316     tracked_object->set_birth_thread_name_hash(
317         MetricsLogBase::Hash(MapThreadName(it->birth.thread_name)));
318     tracked_object->set_exec_thread_name_hash(
319         MetricsLogBase::Hash(MapThreadName(it->death_thread_name)));
320     tracked_object->set_source_file_name_hash(
321         MetricsLogBase::Hash(NormalizeFileName(it->birth.location.file_name)));
322     tracked_object->set_source_function_name_hash(
323         MetricsLogBase::Hash(it->birth.location.function_name));
324     tracked_object->set_source_line_number(it->birth.location.line_number);
325     tracked_object->set_exec_count(death_data.count);
326     tracked_object->set_exec_time_total(death_data.run_duration_sum);
327     tracked_object->set_exec_time_sampled(death_data.run_duration_sample);
328     tracked_object->set_queue_time_total(death_data.queue_duration_sum);
329     tracked_object->set_queue_time_sampled(death_data.queue_duration_sample);
330     tracked_object->set_process_type(AsProtobufProcessType(process_type));
331     tracked_object->set_process_id(profiler_data.process_id);
332   }
333 }
334
335 #if defined(GOOGLE_CHROME_BUILD) && defined(OS_WIN)
336 void ProductDataToProto(const GoogleUpdateSettings::ProductData& product_data,
337                         ProductInfo* product_info) {
338   product_info->set_version(product_data.version);
339   product_info->set_last_update_success_timestamp(
340       product_data.last_success.ToTimeT());
341   product_info->set_last_error(product_data.last_error_code);
342   product_info->set_last_extra_error(product_data.last_extra_code);
343   if (ProductInfo::InstallResult_IsValid(product_data.last_result)) {
344     product_info->set_last_result(
345         static_cast<ProductInfo::InstallResult>(product_data.last_result));
346   }
347 }
348 #endif
349
350 #if defined(OS_WIN)
351 struct ScreenDPIInformation {
352   double max_dpi_x;
353   double max_dpi_y;
354 };
355
356 // Called once for each connected monitor.
357 BOOL CALLBACK GetMonitorDPICallback(HMONITOR, HDC hdc, LPRECT, LPARAM dwData) {
358   const double kMillimetersPerInch = 25.4;
359   ScreenDPIInformation* screen_info =
360       reinterpret_cast<ScreenDPIInformation*>(dwData);
361   // Size of screen, in mm.
362   DWORD size_x = GetDeviceCaps(hdc, HORZSIZE);
363   DWORD size_y = GetDeviceCaps(hdc, VERTSIZE);
364   double dpi_x = (size_x > 0) ?
365       GetDeviceCaps(hdc, HORZRES) / (size_x / kMillimetersPerInch) : 0;
366   double dpi_y = (size_y > 0) ?
367       GetDeviceCaps(hdc, VERTRES) / (size_y / kMillimetersPerInch) : 0;
368   screen_info->max_dpi_x = std::max(dpi_x, screen_info->max_dpi_x);
369   screen_info->max_dpi_y = std::max(dpi_y, screen_info->max_dpi_y);
370   return TRUE;
371 }
372
373 void WriteScreenDPIInformationProto(SystemProfileProto::Hardware* hardware) {
374   HDC desktop_dc = GetDC(NULL);
375   if (desktop_dc) {
376     ScreenDPIInformation si = {0, 0};
377     if (EnumDisplayMonitors(desktop_dc, NULL, GetMonitorDPICallback,
378             reinterpret_cast<LPARAM>(&si))) {
379       hardware->set_max_dpi_x(si.max_dpi_x);
380       hardware->set_max_dpi_y(si.max_dpi_y);
381     }
382     ReleaseDC(GetDesktopWindow(), desktop_dc);
383   }
384 }
385
386 #endif  // defined(OS_WIN)
387
388 // Round a timestamp measured in seconds since epoch to one with a granularity
389 // of an hour. This can be used before uploaded potentially sensitive
390 // timestamps.
391 int64 RoundSecondsToHour(int64 time_in_seconds) {
392   return 3600 * (time_in_seconds / 3600);
393 }
394
395 }  // namespace
396
397 GoogleUpdateMetrics::GoogleUpdateMetrics() : is_system_install(false) {}
398
399 GoogleUpdateMetrics::~GoogleUpdateMetrics() {}
400
401 static base::LazyInstance<std::string>::Leaky
402     g_version_extension = LAZY_INSTANCE_INITIALIZER;
403
404 MetricsLog::MetricsLog(const std::string& client_id,
405                        int session_id,
406                        LogType log_type)
407     : MetricsLogBase(client_id, session_id, log_type,
408                      MetricsLog::GetVersionString()),
409       creation_time_(base::TimeTicks::Now()),
410       extension_metrics_(uma_proto()->client_id()) {
411   uma_proto()->mutable_system_profile()->set_channel(
412       AsProtobufChannel(chrome::VersionInfo::GetChannel()));
413
414 #if defined(OS_CHROMEOS)
415   metrics_log_chromeos_.reset(new MetricsLogChromeOS(uma_proto()));
416 #endif  // OS_CHROMEOS
417 }
418
419 MetricsLog::~MetricsLog() {}
420
421 // static
422 void MetricsLog::RegisterPrefs(PrefRegistrySimple* registry) {
423   registry->RegisterListPref(prefs::kStabilityPluginStats);
424 }
425
426 // static
427 std::string MetricsLog::GetVersionString() {
428   chrome::VersionInfo version_info;
429   if (!version_info.is_valid()) {
430     NOTREACHED() << "Unable to retrieve version info.";
431     return std::string();
432   }
433
434   std::string version = version_info.Version();
435   if (!version_extension().empty())
436     version += version_extension();
437   if (!version_info.IsOfficialBuild())
438     version.append("-devel");
439   return version;
440 }
441
442 // static
443 void MetricsLog::set_version_extension(const std::string& extension) {
444   g_version_extension.Get() = extension;
445 }
446
447 // static
448 const std::string& MetricsLog::version_extension() {
449   return g_version_extension.Get();
450 }
451
452 void MetricsLog::RecordStabilityMetrics(base::TimeDelta incremental_uptime,
453                                         base::TimeDelta uptime) {
454   DCHECK(!locked());
455   DCHECK(HasEnvironment());
456   DCHECK(!HasStabilityMetrics());
457
458   PrefService* pref = GetPrefService();
459   DCHECK(pref);
460
461   // Get stability attributes out of Local State, zeroing out stored values.
462   // NOTE: This could lead to some data loss if this report isn't successfully
463   //       sent, but that's true for all the metrics.
464
465   WriteRequiredStabilityAttributes(pref);
466   WritePluginStabilityElements(pref);
467
468   // Record recent delta for critical stability metrics.  We can't wait for a
469   // restart to gather these, as that delay biases our observation away from
470   // users that run happily for a looooong time.  We send increments with each
471   // uma log upload, just as we send histogram data.
472   WriteRealtimeStabilityAttributes(pref, incremental_uptime, uptime);
473
474   // Omit some stats unless this is the initial stability log.
475   if (log_type() != INITIAL_STABILITY_LOG)
476     return;
477
478   int incomplete_shutdown_count =
479       pref->GetInteger(prefs::kStabilityIncompleteSessionEndCount);
480   pref->SetInteger(prefs::kStabilityIncompleteSessionEndCount, 0);
481   int breakpad_registration_success_count =
482       pref->GetInteger(prefs::kStabilityBreakpadRegistrationSuccess);
483   pref->SetInteger(prefs::kStabilityBreakpadRegistrationSuccess, 0);
484   int breakpad_registration_failure_count =
485       pref->GetInteger(prefs::kStabilityBreakpadRegistrationFail);
486   pref->SetInteger(prefs::kStabilityBreakpadRegistrationFail, 0);
487   int debugger_present_count =
488       pref->GetInteger(prefs::kStabilityDebuggerPresent);
489   pref->SetInteger(prefs::kStabilityDebuggerPresent, 0);
490   int debugger_not_present_count =
491       pref->GetInteger(prefs::kStabilityDebuggerNotPresent);
492   pref->SetInteger(prefs::kStabilityDebuggerNotPresent, 0);
493
494   // TODO(jar): The following are all optional, so we *could* optimize them for
495   // values of zero (and not include them).
496   SystemProfileProto::Stability* stability =
497       uma_proto()->mutable_system_profile()->mutable_stability();
498   stability->set_incomplete_shutdown_count(incomplete_shutdown_count);
499   stability->set_breakpad_registration_success_count(
500       breakpad_registration_success_count);
501   stability->set_breakpad_registration_failure_count(
502       breakpad_registration_failure_count);
503   stability->set_debugger_present_count(debugger_present_count);
504   stability->set_debugger_not_present_count(debugger_not_present_count);
505 }
506
507 PrefService* MetricsLog::GetPrefService() {
508   return g_browser_process->local_state();
509 }
510
511 gfx::Size MetricsLog::GetScreenSize() const {
512   return gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().GetSizeInPixel();
513 }
514
515 float MetricsLog::GetScreenDeviceScaleFactor() const {
516   return gfx::Screen::GetNativeScreen()->
517       GetPrimaryDisplay().device_scale_factor();
518 }
519
520 int MetricsLog::GetScreenCount() const {
521   // TODO(scottmg): NativeScreen maybe wrong. http://crbug.com/133312
522   return gfx::Screen::GetNativeScreen()->GetNumDisplays();
523 }
524
525 void MetricsLog::GetFieldTrialIds(
526     std::vector<ActiveGroupId>* field_trial_ids) const {
527   chrome_variations::GetFieldTrialActiveGroupIds(field_trial_ids);
528 }
529
530 bool MetricsLog::HasEnvironment() const {
531   return uma_proto()->system_profile().has_uma_enabled_date();
532 }
533
534 bool MetricsLog::HasStabilityMetrics() const {
535   return uma_proto()->system_profile().stability().has_launch_count();
536 }
537
538 void MetricsLog::WritePluginStabilityElements(PrefService* pref) {
539   // Now log plugin stability info.
540   const base::ListValue* plugin_stats_list = pref->GetList(
541       prefs::kStabilityPluginStats);
542   if (!plugin_stats_list)
543     return;
544
545 #if defined(ENABLE_PLUGINS)
546   SystemProfileProto::Stability* stability =
547       uma_proto()->mutable_system_profile()->mutable_stability();
548   for (base::ListValue::const_iterator iter = plugin_stats_list->begin();
549        iter != plugin_stats_list->end(); ++iter) {
550     if (!(*iter)->IsType(base::Value::TYPE_DICTIONARY)) {
551       NOTREACHED();
552       continue;
553     }
554     base::DictionaryValue* plugin_dict =
555         static_cast<base::DictionaryValue*>(*iter);
556
557     // Note that this search is potentially a quadratic operation, but given the
558     // low number of plugins installed on a "reasonable" setup, this should be
559     // fine.
560     // TODO(isherman): Verify that this does not show up as a hotspot in
561     // profiler runs.
562     const SystemProfileProto::Plugin* system_profile_plugin = NULL;
563     std::string plugin_name;
564     plugin_dict->GetString(prefs::kStabilityPluginName, &plugin_name);
565     const SystemProfileProto& system_profile = uma_proto()->system_profile();
566     for (int i = 0; i < system_profile.plugin_size(); ++i) {
567       if (system_profile.plugin(i).name() == plugin_name) {
568         system_profile_plugin = &system_profile.plugin(i);
569         break;
570       }
571     }
572
573     if (!system_profile_plugin) {
574       NOTREACHED();
575       continue;
576     }
577
578     SystemProfileProto::Stability::PluginStability* plugin_stability =
579         stability->add_plugin_stability();
580     *plugin_stability->mutable_plugin() = *system_profile_plugin;
581
582     int launches = 0;
583     plugin_dict->GetInteger(prefs::kStabilityPluginLaunches, &launches);
584     if (launches > 0)
585       plugin_stability->set_launch_count(launches);
586
587     int instances = 0;
588     plugin_dict->GetInteger(prefs::kStabilityPluginInstances, &instances);
589     if (instances > 0)
590       plugin_stability->set_instance_count(instances);
591
592     int crashes = 0;
593     plugin_dict->GetInteger(prefs::kStabilityPluginCrashes, &crashes);
594     if (crashes > 0)
595       plugin_stability->set_crash_count(crashes);
596
597     int loading_errors = 0;
598     plugin_dict->GetInteger(prefs::kStabilityPluginLoadingErrors,
599                             &loading_errors);
600     if (loading_errors > 0)
601       plugin_stability->set_loading_error_count(loading_errors);
602   }
603 #endif  // defined(ENABLE_PLUGINS)
604
605   pref->ClearPref(prefs::kStabilityPluginStats);
606 }
607
608 // The server refuses data that doesn't have certain values.  crashcount and
609 // launchcount are currently "required" in the "stability" group.
610 // TODO(isherman): Stop writing these attributes specially once the migration to
611 // protobufs is complete.
612 void MetricsLog::WriteRequiredStabilityAttributes(PrefService* pref) {
613   int launch_count = pref->GetInteger(prefs::kStabilityLaunchCount);
614   pref->SetInteger(prefs::kStabilityLaunchCount, 0);
615   int crash_count = pref->GetInteger(prefs::kStabilityCrashCount);
616   pref->SetInteger(prefs::kStabilityCrashCount, 0);
617
618   SystemProfileProto::Stability* stability =
619       uma_proto()->mutable_system_profile()->mutable_stability();
620   stability->set_launch_count(launch_count);
621   stability->set_crash_count(crash_count);
622 }
623
624 void MetricsLog::WriteRealtimeStabilityAttributes(
625     PrefService* pref,
626     base::TimeDelta incremental_uptime,
627     base::TimeDelta uptime) {
628   // Update the stats which are critical for real-time stability monitoring.
629   // Since these are "optional," only list ones that are non-zero, as the counts
630   // are aggregated (summed) server side.
631
632   SystemProfileProto::Stability* stability =
633       uma_proto()->mutable_system_profile()->mutable_stability();
634   int count = pref->GetInteger(prefs::kStabilityPageLoadCount);
635   if (count) {
636     stability->set_page_load_count(count);
637     pref->SetInteger(prefs::kStabilityPageLoadCount, 0);
638   }
639
640   count = pref->GetInteger(prefs::kStabilityRendererCrashCount);
641   if (count) {
642     stability->set_renderer_crash_count(count);
643     pref->SetInteger(prefs::kStabilityRendererCrashCount, 0);
644   }
645
646   count = pref->GetInteger(prefs::kStabilityExtensionRendererCrashCount);
647   if (count) {
648     stability->set_extension_renderer_crash_count(count);
649     pref->SetInteger(prefs::kStabilityExtensionRendererCrashCount, 0);
650   }
651
652   count = pref->GetInteger(prefs::kStabilityRendererHangCount);
653   if (count) {
654     stability->set_renderer_hang_count(count);
655     pref->SetInteger(prefs::kStabilityRendererHangCount, 0);
656   }
657
658   count = pref->GetInteger(prefs::kStabilityChildProcessCrashCount);
659   if (count) {
660     stability->set_child_process_crash_count(count);
661     pref->SetInteger(prefs::kStabilityChildProcessCrashCount, 0);
662   }
663
664 #if defined(OS_CHROMEOS)
665   metrics_log_chromeos_->WriteRealtimeStabilityAttributes(pref);
666 #endif  // OS_CHROMEOS
667
668   const uint64 incremental_uptime_sec = incremental_uptime.InSeconds();
669   if (incremental_uptime_sec)
670     stability->set_incremental_uptime_sec(incremental_uptime_sec);
671   const uint64 uptime_sec = uptime.InSeconds();
672   if (uptime_sec)
673     stability->set_uptime_sec(uptime_sec);
674 }
675
676 void MetricsLog::WritePluginList(
677     const std::vector<content::WebPluginInfo>& plugin_list) {
678   DCHECK(!locked());
679
680 #if defined(ENABLE_PLUGINS)
681   PluginPrefs* plugin_prefs = GetPluginPrefs();
682   SystemProfileProto* system_profile = uma_proto()->mutable_system_profile();
683   for (std::vector<content::WebPluginInfo>::const_iterator iter =
684            plugin_list.begin();
685        iter != plugin_list.end(); ++iter) {
686     SystemProfileProto::Plugin* plugin = system_profile->add_plugin();
687     SetPluginInfo(*iter, plugin_prefs, plugin);
688   }
689 #endif  // defined(ENABLE_PLUGINS)
690 }
691
692 void MetricsLog::RecordEnvironment(
693     const std::vector<content::WebPluginInfo>& plugin_list,
694     const GoogleUpdateMetrics& google_update_metrics,
695     const std::vector<chrome_variations::ActiveGroupId>& synthetic_trials) {
696   DCHECK(!HasEnvironment());
697
698   SystemProfileProto* system_profile = uma_proto()->mutable_system_profile();
699
700   std::string brand_code;
701   if (google_util::GetBrand(&brand_code))
702     system_profile->set_brand_code(brand_code);
703
704   int enabled_date;
705   bool success = base::StringToInt(GetMetricsEnabledDate(GetPrefService()),
706                                    &enabled_date);
707   DCHECK(success);
708
709   // Reduce granularity of the enabled_date field to nearest hour.
710   system_profile->set_uma_enabled_date(RoundSecondsToHour(enabled_date));
711
712   int64 install_date = GetPrefService()->GetInt64(prefs::kInstallDate);
713
714   // Reduce granularity of the install_date field to nearest hour.
715   system_profile->set_install_date(RoundSecondsToHour(install_date));
716
717   system_profile->set_application_locale(
718       g_browser_process->GetApplicationLocale());
719
720   SystemProfileProto::Hardware* hardware = system_profile->mutable_hardware();
721   hardware->set_cpu_architecture(base::SysInfo::OperatingSystemArchitecture());
722   hardware->set_system_ram_mb(base::SysInfo::AmountOfPhysicalMemoryMB());
723 #if defined(OS_WIN)
724   hardware->set_dll_base(reinterpret_cast<uint64>(&__ImageBase));
725 #endif
726
727   SystemProfileProto::Network* network = system_profile->mutable_network();
728   network->set_connection_type_is_ambiguous(
729       network_observer_.connection_type_is_ambiguous());
730   network->set_connection_type(network_observer_.connection_type());
731   network->set_wifi_phy_layer_protocol_is_ambiguous(
732       network_observer_.wifi_phy_layer_protocol_is_ambiguous());
733   network->set_wifi_phy_layer_protocol(
734       network_observer_.wifi_phy_layer_protocol());
735   network_observer_.Reset();
736
737   SystemProfileProto::OS* os = system_profile->mutable_os();
738   std::string os_name = base::SysInfo::OperatingSystemName();
739 #if defined(OS_WIN)
740   // TODO(mad): This only checks whether the main process is a Metro process at
741   // upload time; not whether the collected metrics were all gathered from
742   // Metro.  This is ok as an approximation for now, since users will rarely be
743   // switching from Metro to Desktop mode; but we should re-evaluate whether we
744   // can distinguish metrics more cleanly in the future: http://crbug.com/140568
745   if (base::win::IsMetroProcess())
746     os_name += " (Metro)";
747 #endif
748   os->set_name(os_name);
749   os->set_version(base::SysInfo::OperatingSystemVersion());
750 #if defined(OS_ANDROID)
751   os->set_fingerprint(
752       base::android::BuildInfo::GetInstance()->android_build_fp());
753 #endif
754
755   base::CPU cpu_info;
756   SystemProfileProto::Hardware::CPU* cpu = hardware->mutable_cpu();
757   cpu->set_vendor_name(cpu_info.vendor_name());
758   cpu->set_signature(cpu_info.signature());
759
760   const gpu::GPUInfo& gpu_info =
761       GpuDataManager::GetInstance()->GetGPUInfo();
762   SystemProfileProto::Hardware::Graphics* gpu = hardware->mutable_gpu();
763   gpu->set_vendor_id(gpu_info.gpu.vendor_id);
764   gpu->set_device_id(gpu_info.gpu.device_id);
765   gpu->set_driver_version(gpu_info.driver_version);
766   gpu->set_driver_date(gpu_info.driver_date);
767   SystemProfileProto::Hardware::Graphics::PerformanceStatistics*
768       gpu_performance = gpu->mutable_performance_statistics();
769   gpu_performance->set_graphics_score(gpu_info.performance_stats.graphics);
770   gpu_performance->set_gaming_score(gpu_info.performance_stats.gaming);
771   gpu_performance->set_overall_score(gpu_info.performance_stats.overall);
772   gpu->set_gl_vendor(gpu_info.gl_vendor);
773   gpu->set_gl_renderer(gpu_info.gl_renderer);
774
775   const gfx::Size display_size = GetScreenSize();
776   hardware->set_primary_screen_width(display_size.width());
777   hardware->set_primary_screen_height(display_size.height());
778   hardware->set_primary_screen_scale_factor(GetScreenDeviceScaleFactor());
779   hardware->set_screen_count(GetScreenCount());
780
781 #if defined(OS_WIN)
782   WriteScreenDPIInformationProto(hardware);
783 #endif
784
785   WriteGoogleUpdateProto(google_update_metrics);
786
787   WritePluginList(plugin_list);
788   extension_metrics_.WriteExtensionList(uma_proto()->mutable_system_profile());
789
790   std::vector<ActiveGroupId> field_trial_ids;
791   GetFieldTrialIds(&field_trial_ids);
792   WriteFieldTrials(field_trial_ids, system_profile);
793   WriteFieldTrials(synthetic_trials, system_profile);
794
795 #if defined(OS_CHROMEOS)
796   metrics_log_chromeos_->LogChromeOSMetrics();
797 #endif  // OS_CHROMEOS
798
799   std::string serialied_system_profile;
800   std::string base64_system_profile;
801   if (system_profile->SerializeToString(&serialied_system_profile)) {
802     base::Base64Encode(serialied_system_profile, &base64_system_profile);
803     PrefService* local_state = GetPrefService();
804     local_state->SetString(prefs::kStabilitySavedSystemProfile,
805                            base64_system_profile);
806     local_state->SetString(prefs::kStabilitySavedSystemProfileHash,
807                            ComputeSHA1(serialied_system_profile));
808   }
809 }
810
811 bool MetricsLog::LoadSavedEnvironmentFromPrefs() {
812   PrefService* local_state = GetPrefService();
813   const std::string base64_system_profile =
814       local_state->GetString(prefs::kStabilitySavedSystemProfile);
815   if (base64_system_profile.empty())
816     return false;
817
818   const std::string system_profile_hash =
819       local_state->GetString(prefs::kStabilitySavedSystemProfileHash);
820   local_state->ClearPref(prefs::kStabilitySavedSystemProfile);
821   local_state->ClearPref(prefs::kStabilitySavedSystemProfileHash);
822
823   SystemProfileProto* system_profile = uma_proto()->mutable_system_profile();
824   std::string serialied_system_profile;
825   return base::Base64Decode(base64_system_profile, &serialied_system_profile) &&
826          ComputeSHA1(serialied_system_profile) == system_profile_hash &&
827          system_profile->ParseFromString(serialied_system_profile);
828 }
829
830 void MetricsLog::RecordProfilerData(
831     const tracked_objects::ProcessDataSnapshot& process_data,
832     int process_type) {
833   DCHECK(!locked());
834
835   if (tracked_objects::GetTimeSourceType() !=
836           tracked_objects::TIME_SOURCE_TYPE_WALL_TIME) {
837     // We currently only support the default time source, wall clock time.
838     return;
839   }
840
841   ProfilerEventProto* profile;
842   if (!uma_proto()->profiler_event_size()) {
843     // For the first process's data, add a new field to the protocol buffer.
844     profile = uma_proto()->add_profiler_event();
845     profile->set_profile_type(ProfilerEventProto::STARTUP_PROFILE);
846     profile->set_time_source(ProfilerEventProto::WALL_CLOCK_TIME);
847   } else {
848     // For the remaining calls, re-use the existing field.
849     profile = uma_proto()->mutable_profiler_event(0);
850   }
851
852   WriteProfilerData(process_data, process_type, profile);
853 }
854
855 void MetricsLog::RecordOmniboxOpenedURL(const OmniboxLog& log) {
856   DCHECK(!locked());
857
858   std::vector<base::string16> terms;
859   const int num_terms =
860       static_cast<int>(Tokenize(log.text, base::kWhitespaceUTF16, &terms));
861
862   OmniboxEventProto* omnibox_event = uma_proto()->add_omnibox_event();
863   omnibox_event->set_time(MetricsLogBase::GetCurrentTime());
864   if (log.tab_id != -1) {
865     // If we know what tab the autocomplete URL was opened in, log it.
866     omnibox_event->set_tab_id(log.tab_id);
867   }
868   omnibox_event->set_typed_length(log.text.length());
869   omnibox_event->set_just_deleted_text(log.just_deleted_text);
870   omnibox_event->set_num_typed_terms(num_terms);
871   omnibox_event->set_selected_index(log.selected_index);
872   if (log.completed_length != base::string16::npos)
873     omnibox_event->set_completed_length(log.completed_length);
874   const base::TimeDelta default_time_delta =
875       base::TimeDelta::FromMilliseconds(-1);
876   if (log.elapsed_time_since_user_first_modified_omnibox !=
877       default_time_delta) {
878     // Only upload the typing duration if it is set/valid.
879     omnibox_event->set_typing_duration_ms(
880         log.elapsed_time_since_user_first_modified_omnibox.InMilliseconds());
881   }
882   if (log.elapsed_time_since_last_change_to_default_match !=
883       default_time_delta) {
884     omnibox_event->set_duration_since_last_default_match_update_ms(
885         log.elapsed_time_since_last_change_to_default_match.InMilliseconds());
886   }
887   omnibox_event->set_current_page_classification(
888       AsOmniboxEventPageClassification(log.current_page_classification));
889   omnibox_event->set_input_type(AsOmniboxEventInputType(log.input_type));
890   // We consider a paste-and-search/paste-and-go action to have a closed popup
891   // (as explained in omnibox_event.proto) even if it was not, because such
892   // actions ignore the contents of the popup so it doesn't matter that it was
893   // open.
894   const bool consider_popup_open = log.is_popup_open && !log.is_paste_and_go;
895   omnibox_event->set_is_popup_open(consider_popup_open);
896   omnibox_event->set_is_paste_and_go(log.is_paste_and_go);
897   if (consider_popup_open) {
898     omnibox_event->set_is_top_result_hidden_in_dropdown(
899         log.result.ShouldHideTopMatch());
900   }
901
902   for (AutocompleteResult::const_iterator i(log.result.begin());
903        i != log.result.end(); ++i) {
904     OmniboxEventProto::Suggestion* suggestion = omnibox_event->add_suggestion();
905     suggestion->set_provider(i->provider->AsOmniboxEventProviderType());
906     suggestion->set_result_type(AsOmniboxEventResultType(i->type));
907     suggestion->set_relevance(i->relevance);
908     if (i->typed_count != -1)
909       suggestion->set_typed_count(i->typed_count);
910     suggestion->set_is_starred(i->starred);
911   }
912   for (ProvidersInfo::const_iterator i(log.providers_info.begin());
913        i != log.providers_info.end(); ++i) {
914     OmniboxEventProto::ProviderInfo* provider_info =
915         omnibox_event->add_provider_info();
916     provider_info->CopyFrom(*i);
917   }
918
919   ++num_events_;
920 }
921
922 void MetricsLog::WriteGoogleUpdateProto(
923     const GoogleUpdateMetrics& google_update_metrics) {
924 #if defined(GOOGLE_CHROME_BUILD) && defined(OS_WIN)
925   SystemProfileProto::GoogleUpdate* google_update =
926       uma_proto()->mutable_system_profile()->mutable_google_update();
927
928   google_update->set_is_system_install(google_update_metrics.is_system_install);
929
930   if (!google_update_metrics.last_started_au.is_null()) {
931     google_update->set_last_automatic_start_timestamp(
932         google_update_metrics.last_started_au.ToTimeT());
933   }
934
935   if (!google_update_metrics.last_checked.is_null()) {
936     google_update->set_last_update_check_timestamp(
937       google_update_metrics.last_checked.ToTimeT());
938   }
939
940   if (!google_update_metrics.google_update_data.version.empty()) {
941     ProductDataToProto(google_update_metrics.google_update_data,
942                        google_update->mutable_google_update_status());
943   }
944
945   if (!google_update_metrics.product_data.version.empty()) {
946     ProductDataToProto(google_update_metrics.product_data,
947                        google_update->mutable_client_status());
948   }
949 #endif  // defined(GOOGLE_CHROME_BUILD) && defined(OS_WIN)
950 }