blob: 9e8fcd50fc102640a96736b5f8f1e2e3251dbb39 [file] [log] [blame]
[email protected]2e4cd1a2012-01-12 08:51:031// Copyright (c) 2012 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit09911bf2008-07-26 23:55:294
initial.commit09911bf2008-07-26 23:55:295//------------------------------------------------------------------------------
6// Description of the life cycle of a instance of MetricsService.
7//
8// OVERVIEW
9//
[email protected]e3eb0c42013-04-18 06:18:5810// A MetricsService instance is typically created at application startup. It is
11// the central controller for the acquisition of log data, and the automatic
initial.commit09911bf2008-07-26 23:55:2912// transmission of that log data to an external server. Its major job is to
13// manage logs, grouping them for transmission, and transmitting them. As part
14// of its grouping, MS finalizes logs by including some just-in-time gathered
15// memory statistics, snapshotting the current stats of numerous histograms,
[email protected]e3eb0c42013-04-18 06:18:5816// closing the logs, translating to protocol buffer format, and compressing the
17// results for transmission. Transmission includes submitting a compressed log
18// as data in a URL-post, and retransmitting (or retaining at process
19// termination) if the attempted transmission failed. Retention across process
20// terminations is done using the the PrefServices facilities. The retained logs
21// (the ones that never got transmitted) are compressed and base64-encoded
22// before being persisted.
initial.commit09911bf2008-07-26 23:55:2923//
[email protected]281d2882009-01-20 20:32:4224// Logs fall into one of two categories: "initial logs," and "ongoing logs."
[email protected]80a8f312013-12-16 18:00:3025// There is at most one initial log sent for each complete run of Chrome (from
26// startup, to browser shutdown). An initial log is generally transmitted some
27// short time (1 minute?) after startup, and includes stats such as recent crash
28// info, the number and types of plugins, etc. The external server's response
29// to the initial log conceptually tells this MS if it should continue
30// transmitting logs (during this session). The server response can actually be
31// much more detailed, and always includes (at a minimum) how often additional
32// ongoing logs should be sent.
initial.commit09911bf2008-07-26 23:55:2933//
34// After the above initial log, a series of ongoing logs will be transmitted.
35// The first ongoing log actually begins to accumulate information stating when
36// the MS was first constructed. Note that even though the initial log is
37// commonly sent a full minute after startup, the initial log does not include
38// much in the way of user stats. The most common interlog period (delay)
[email protected]3a668152013-06-21 23:56:4239// is 30 minutes. That time period starts when the first user action causes a
initial.commit09911bf2008-07-26 23:55:2940// logging event. This means that if there is no user action, there may be long
[email protected]281d2882009-01-20 20:32:4241// periods without any (ongoing) log transmissions. Ongoing logs typically
initial.commit09911bf2008-07-26 23:55:2942// contain very detailed records of user activities (ex: opened tab, closed
43// tab, fetched URL, maximized window, etc.) In addition, just before an
44// ongoing log is closed out, a call is made to gather memory statistics. Those
45// memory statistics are deposited into a histogram, and the log finalization
46// code is then called. In the finalization, a call to a Histogram server
47// acquires a list of all local histograms that have been flagged for upload
[email protected]80a8f312013-12-16 18:00:3048// to the UMA server. The finalization also acquires the most recent number
[email protected]281d2882009-01-20 20:32:4249// of page loads, along with any counts of renderer or plugin crashes.
initial.commit09911bf2008-07-26 23:55:2950//
51// When the browser shuts down, there will typically be a fragment of an ongoing
[email protected]80a8f312013-12-16 18:00:3052// log that has not yet been transmitted. At shutdown time, that fragment is
53// closed (including snapshotting histograms), and persisted, for potential
54// transmission during a future run of the product.
initial.commit09911bf2008-07-26 23:55:2955//
56// There are two slightly abnormal shutdown conditions. There is a
57// "disconnected scenario," and a "really fast startup and shutdown" scenario.
58// In the "never connected" situation, the user has (during the running of the
59// process) never established an internet connection. As a result, attempts to
60// transmit the initial log have failed, and a lot(?) of data has accumulated in
61// the ongoing log (which didn't yet get closed, because there was never even a
62// contemplation of sending it). There is also a kindred "lost connection"
63// situation, where a loss of connection prevented an ongoing log from being
64// transmitted, and a (still open) log was stuck accumulating a lot(?) of data,
65// while the earlier log retried its transmission. In both of these
66// disconnected situations, two logs need to be, and are, persistently stored
67// for future transmission.
68//
69// The other unusual shutdown condition, termed "really fast startup and
70// shutdown," involves the deliberate user termination of the process before
71// the initial log is even formed or transmitted. In that situation, no logging
72// is done, but the historical crash statistics remain (unlogged) for inclusion
73// in a future run's initial log. (i.e., we don't lose crash stats).
74//
75// With the above overview, we can now describe the state machine's various
[email protected]80a8f312013-12-16 18:00:3076// states, based on the State enum specified in the state_ member. Those states
initial.commit09911bf2008-07-26 23:55:2977// are:
78//
[email protected]80a8f312013-12-16 18:00:3079// INITIALIZED, // Constructor was called.
80// INIT_TASK_SCHEDULED, // Waiting for deferred init tasks to finish.
81// INIT_TASK_DONE, // Waiting for timer to send initial log.
82// SENDING_INITIAL_STABILITY_LOG, // Initial stability log being sent.
83// SENDING_INITIAL_METRICS_LOG, // Initial metrics log being sent.
84// SENDING_OLD_LOGS, // Sending unsent logs from previous session.
85// SENDING_CURRENT_LOGS, // Sending ongoing logs as they acrue.
initial.commit09911bf2008-07-26 23:55:2986//
87// In more detail, we have:
88//
89// INITIALIZED, // Constructor was called.
90// The MS has been constructed, but has taken no actions to compose the
91// initial log.
92//
[email protected]80a8f312013-12-16 18:00:3093// INIT_TASK_SCHEDULED, // Waiting for deferred init tasks to finish.
initial.commit09911bf2008-07-26 23:55:2994// Typically about 30 seconds after startup, a task is sent to a second thread
[email protected]85ed9d42010-06-08 22:37:4495// (the file thread) to perform deferred (lower priority and slower)
96// initialization steps such as getting the list of plugins. That task will
97// (when complete) make an async callback (via a Task) to indicate the
98// completion.
initial.commit09911bf2008-07-26 23:55:2999//
[email protected]85ed9d42010-06-08 22:37:44100// INIT_TASK_DONE, // Waiting for timer to send initial log.
initial.commit09911bf2008-07-26 23:55:29101// The callback has arrived, and it is now possible for an initial log to be
102// created. This callback typically arrives back less than one second after
[email protected]85ed9d42010-06-08 22:37:44103// the deferred init task is dispatched.
initial.commit09911bf2008-07-26 23:55:29104//
[email protected]80a8f312013-12-16 18:00:30105// SENDING_INITIAL_STABILITY_LOG, // Initial stability log being sent.
106// During initialization, if a crash occurred during the previous session, an
107// initial stability log will be generated and registered with the log manager.
108// This state will be entered if a stability log was prepared during metrics
109// service initialization (in InitializeMetricsRecordingState()) and is waiting
110// to be transmitted when it's time to send up the first log (per the reporting
111// scheduler). If there is no initial stability log (e.g. there was no previous
112// crash), then this state will be skipped and the state will advance to
113// SENDING_INITIAL_METRICS_LOG.
114//
115// SENDING_INITIAL_METRICS_LOG, // Initial metrics log being sent.
116// This state is entered after the initial metrics log has been composed, and
117// prepared for transmission. This happens after SENDING_INITIAL_STABILITY_LOG
118// if there was an initial stability log (see above). It is also the case that
119// any previously unsent logs have been loaded into instance variables for
120// possible transmission.
initial.commit09911bf2008-07-26 23:55:29121//
initial.commit09911bf2008-07-26 23:55:29122// SENDING_OLD_LOGS, // Sending unsent logs from previous session.
[email protected]cac267c2011-09-29 15:18:10123// This state indicates that the initial log for this session has been
124// successfully sent and it is now time to send any logs that were
125// saved from previous sessions. All such logs will be transmitted before
126// exiting this state, and proceeding with ongoing logs from the current session
127// (see next state).
initial.commit09911bf2008-07-26 23:55:29128//
129// SENDING_CURRENT_LOGS, // Sending standard current logs as they accrue.
[email protected]0b33f80b2008-12-17 21:34:36130// Current logs are being accumulated. Typically every 20 minutes a log is
initial.commit09911bf2008-07-26 23:55:29131// closed and finalized for transmission, at the same time as a new log is
132// started.
133//
134// The progression through the above states is simple, and sequential, in the
135// most common use cases. States proceed from INITIAL to SENDING_CURRENT_LOGS,
136// and remain in the latter until shutdown.
137//
138// The one unusual case is when the user asks that we stop logging. When that
[email protected]cac267c2011-09-29 15:18:10139// happens, any staged (transmission in progress) log is persisted, and any log
[email protected]410938e02012-10-24 16:33:59140// that is currently accumulating is also finalized and persisted. We then
[email protected]cac267c2011-09-29 15:18:10141// regress back to the SEND_OLD_LOGS state in case the user enables log
142// recording again during this session. This way anything we have persisted
143// will be sent automatically if/when we progress back to SENDING_CURRENT_LOG
144// state.
initial.commit09911bf2008-07-26 23:55:29145//
[email protected]410938e02012-10-24 16:33:59146// Another similar case is on mobile, when the application is backgrounded and
147// then foregrounded again. Backgrounding created new "old" stored logs, so the
148// state drops back from SENDING_CURRENT_LOGS to SENDING_OLD_LOGS so those logs
149// will be sent.
150//
[email protected]cac267c2011-09-29 15:18:10151// Also note that whenever we successfully send an old log, we mirror the list
152// of logs into the PrefService. This ensures that IF we crash, we won't start
153// up and retransmit our old logs again.
initial.commit09911bf2008-07-26 23:55:29154//
155// Due to race conditions, it is always possible that a log file could be sent
156// twice. For example, if a log file is sent, but not yet acknowledged by
157// the external server, and the user shuts down, then a copy of the log may be
158// saved for re-transmission. These duplicates could be filtered out server
[email protected]281d2882009-01-20 20:32:42159// side, but are not expected to be a significant problem.
initial.commit09911bf2008-07-26 23:55:29160//
161//
162//------------------------------------------------------------------------------
163
[email protected]40bcc302009-03-02 20:50:39164#include "chrome/browser/metrics/metrics_service.h"
165
[email protected]d7c1fa62012-06-15 23:35:30166#include <algorithm>
167
[email protected]7f7f1962011-04-20 15:58:16168#include "base/bind.h"
169#include "base/callback.h"
[email protected]5d91c9e2010-07-28 17:25:28170#include "base/command_line.h"
[email protected]835d7c82010-10-14 04:38:38171#include "base/metrics/histogram.h"
[email protected]1026afd2013-03-20 14:28:54172#include "base/metrics/sparse_histogram.h"
[email protected]567d30e2012-07-13 21:48:29173#include "base/metrics/statistics_recorder.h"
[email protected]3853a4c2013-02-11 17:15:57174#include "base/prefs/pref_registry_simple.h"
175#include "base/prefs/pref_service.h"
[email protected]9eec53fe2013-10-30 20:21:17176#include "base/prefs/scoped_user_pref_update.h"
[email protected]3ea1b182013-02-08 22:38:41177#include "base/strings/string_number_conversions.h"
[email protected]112158af2013-06-07 23:46:18178#include "base/strings/utf_string_conversions.h"
[email protected]ce072a72010-12-31 20:02:16179#include "base/threading/platform_thread.h"
[email protected]b3841c502011-03-09 01:21:31180#include "base/threading/thread.h"
[email protected]3a7b66d2012-04-26 16:34:16181#include "base/threading/thread_restrictions.h"
[email protected]ed0fd002012-04-25 23:10:34182#include "base/tracked_objects.h"
[email protected]679082052010-07-21 21:30:13183#include "base/values.h"
initial.commit09911bf2008-07-26 23:55:29184#include "chrome/browser/browser_process.h"
[email protected]9ea0cd32013-07-12 01:50:36185#include "chrome/browser/chrome_notification_types.h"
[email protected]b8ddb052012-04-19 02:36:06186#include "chrome/browser/io_thread.h"
[email protected]84c988a2011-04-19 17:56:33187#include "chrome/browser/memory_details.h"
[email protected]537c638d2013-07-04 00:49:19188#include "chrome/browser/metrics/compression_utils.h"
[email protected]679082052010-07-21 21:30:13189#include "chrome/browser/metrics/metrics_log.h"
[email protected]7f7f1962011-04-20 15:58:16190#include "chrome/browser/metrics/metrics_reporting_scheduler.h"
[email protected]39076642014-05-05 20:32:55191#include "chrome/browser/metrics/metrics_state_manager.h"
[email protected]aa312812013-04-30 19:46:05192#include "chrome/browser/metrics/time_ticks_experiment_win.h"
[email protected]ed0fd002012-04-25 23:10:34193#include "chrome/browser/metrics/tracking_synchronizer.h"
[email protected]60677562013-11-17 15:52:55194#include "chrome/common/metrics/variations/variations_util.h"
[email protected]adbb3762012-03-09 22:20:08195#include "chrome/browser/net/http_pipelining_compatibility_client.h"
[email protected]d67d1052011-06-09 05:11:41196#include "chrome/browser/net/network_stats.h"
[email protected]0fafc8d2013-06-01 00:09:50197#include "chrome/browser/omnibox/omnibox_log.h"
[email protected]10b132b02012-07-27 20:46:18198#include "chrome/browser/ui/browser_otr_state.h"
[email protected]261ab7c2013-08-19 15:04:58199#include "chrome/common/chrome_constants.h"
[email protected]92745242009-06-12 16:52:21200#include "chrome/common/chrome_switches.h"
[email protected]264c0acac2013-10-01 13:33:30201#include "chrome/common/crash_keys.h"
[email protected]b4a72d842012-03-22 20:09:09202#include "chrome/common/net/test_server_locations.h"
initial.commit09911bf2008-07-26 23:55:29203#include "chrome/common/pref_names.h"
[email protected]e09ba552009-02-05 03:26:29204#include "chrome/common/render_messages.h"
[email protected]064107e2014-05-02 00:59:06205#include "components/metrics/metrics_log_manager.h"
[email protected]7f07db62014-05-15 01:12:45206#include "components/metrics/metrics_pref_names.h"
[email protected]50ae9f12013-08-29 18:03:22207#include "components/variations/entropy_provider.h"
[email protected]60677562013-11-17 15:52:55208#include "components/variations/metrics_util.h"
[email protected]4967f792012-01-20 22:14:40209#include "content/public/browser/child_process_data.h"
[email protected]83ab4a282012-07-12 18:19:45210#include "content/public/browser/histogram_fetcher.h"
[email protected]09d31d52012-03-11 22:30:27211#include "content/public/browser/load_notification_details.h"
[email protected]ad50def52011-10-19 23:17:07212#include "content/public/browser/notification_service.h"
[email protected]3a5180ae2011-12-21 02:39:38213#include "content/public/browser/plugin_service.h"
[email protected]f3b1a082011-11-18 00:34:30214#include "content/public/browser/render_process_host.h"
[email protected]5d490e42012-08-30 05:16:43215#include "content/public/browser/user_metrics.h"
[email protected]459f3502012-09-17 17:08:12216#include "content/public/browser/web_contents.h"
[email protected]d5d383252013-07-04 14:44:32217#include "content/public/common/process_type.h"
[email protected]d7bd3e52013-07-21 04:29:20218#include "content/public/common/webplugininfo.h"
[email protected]50de9aa22013-11-14 06:30:34219#include "extensions/browser/process_map.h"
[email protected]fe58acc22012-02-29 01:29:58220#include "net/base/load_flags.h"
[email protected]3dc1bc42012-06-19 08:20:53221#include "net/url_request/url_fetcher.h"
initial.commit09911bf2008-07-26 23:55:29222
[email protected]e06131d2010-02-10 18:40:33223// TODO(port): port browser_distribution.h.
224#if !defined(OS_POSIX)
[email protected]79bf0b72009-04-27 21:30:55225#include "chrome/installer/util/browser_distribution.h"
[email protected]dc6f4962009-02-13 01:25:50226#endif
227
[email protected]5ccaa412009-11-13 22:00:16228#if defined(OS_CHROMEOS)
229#include "chrome/browser/chromeos/external_metrics.h"
[email protected]1ef13cf2014-03-21 22:44:01230#include "chrome/browser/chromeos/settings/cros_settings.h"
[email protected]279690f82013-10-09 08:23:52231#include "chromeos/system/statistics_provider.h"
[email protected]5ccaa412009-11-13 22:00:16232#endif
233
[email protected]d7c1fa62012-06-15 23:35:30234#if defined(OS_WIN)
235#include <windows.h> // Needed for STATUS_* codes
[email protected]261ab7c2013-08-19 15:04:58236#include "base/win/registry.h"
[email protected]d7c1fa62012-06-15 23:35:30237#endif
238
[email protected]a3079832013-10-24 20:29:36239#if !defined(OS_ANDROID)
[email protected]cbf160aa2013-11-05 17:54:55240#include "chrome/browser/service_process/service_process_control.h"
[email protected]a3079832013-10-24 20:29:36241#endif
242
[email protected]e1acf6f2008-10-27 20:43:33243using base::Time;
[email protected]631bb742011-11-02 11:29:39244using content::BrowserThread;
[email protected]4967f792012-01-20 22:14:40245using content::ChildProcessData;
[email protected]09d31d52012-03-11 22:30:27246using content::LoadNotificationDetails;
[email protected]3a5180ae2011-12-21 02:39:38247using content::PluginService;
[email protected]064107e2014-05-02 00:59:06248using metrics::MetricsLogManager;
[email protected]e1acf6f2008-10-27 20:43:33249
[email protected]fe58acc22012-02-29 01:29:58250namespace {
[email protected]b2a4812d2012-02-28 05:31:31251
[email protected]fe58acc22012-02-29 01:29:58252// Check to see that we're being called on only one thread.
253bool IsSingleThreaded() {
254 static base::PlatformThreadId thread_id = 0;
255 if (!thread_id)
256 thread_id = base::PlatformThread::CurrentId();
257 return base::PlatformThread::CurrentId() == thread_id;
258}
259
[email protected]7f7f1962011-04-20 15:58:16260// The delay, in seconds, after starting recording before doing expensive
261// initialization work.
[email protected]12180f82012-10-10 21:13:30262#if defined(OS_ANDROID) || defined(OS_IOS)
263// On mobile devices, a significant portion of sessions last less than a minute.
264// Use a shorter timer on these platforms to avoid losing data.
265// TODO(dfalcantara): To avoid delaying startup, tighten up initialization so
266// that it occurs after the user gets their initial page.
267const int kInitializationDelaySeconds = 5;
268#else
[email protected]fe58acc22012-02-29 01:29:58269const int kInitializationDelaySeconds = 30;
[email protected]12180f82012-10-10 21:13:30270#endif
[email protected]252873ef2008-08-04 21:59:45271
[email protected]c9a3ef82009-05-28 22:02:46272// This specifies the amount of time to wait for all renderers to send their
273// data.
[email protected]fe58acc22012-02-29 01:29:58274const int kMaxHistogramGatheringWaitDuration = 60000; // 60 seconds.
[email protected]c9a3ef82009-05-28 22:02:46275
[email protected]54702c92011-04-15 15:06:43276// The maximum number of events in a log uploaded to the UMA server.
[email protected]fe58acc22012-02-29 01:29:58277const int kEventLimit = 2400;
[email protected]68475e602008-08-22 03:21:15278
279// If an upload fails, and the transmission was over this byte count, then we
280// will discard the log, and not try to retransmit it. We also don't persist
281// the log to the prefs for transmission during the next chrome session if this
282// limit is exceeded.
[email protected]fe58acc22012-02-29 01:29:58283const size_t kUploadLogAvoidRetransmitSize = 50000;
initial.commit09911bf2008-07-26 23:55:29284
[email protected]fc4252a72012-01-12 21:58:47285// Interval, in minutes, between state saves.
[email protected]fe58acc22012-02-29 01:29:58286const int kSaveStateIntervalMinutes = 5;
287
[email protected]4266def22012-05-17 01:02:40288enum ResponseStatus {
289 UNKNOWN_FAILURE,
290 SUCCESS,
291 BAD_REQUEST, // Invalid syntax or log too large.
[email protected]9f5c1ce82012-05-23 23:11:28292 NO_RESPONSE,
[email protected]4266def22012-05-17 01:02:40293 NUM_RESPONSE_STATUSES
294};
295
296ResponseStatus ResponseCodeToStatus(int response_code) {
297 switch (response_code) {
298 case 200:
299 return SUCCESS;
300 case 400:
301 return BAD_REQUEST;
[email protected]9f5c1ce82012-05-23 23:11:28302 case net::URLFetcher::RESPONSE_CODE_INVALID:
303 return NO_RESPONSE;
[email protected]4266def22012-05-17 01:02:40304 default:
305 return UNKNOWN_FAILURE;
306 }
307}
308
[email protected]d7c1fa62012-06-15 23:35:30309// Converts an exit code into something that can be inserted into our
310// histograms (which expect non-negative numbers less than MAX_INT).
311int MapCrashExitCodeForHistogram(int exit_code) {
312#if defined(OS_WIN)
313 // Since |abs(STATUS_GUARD_PAGE_VIOLATION) == MAX_INT| it causes problems in
314 // histograms.cc. Solve this by remapping it to a smaller value, which
315 // hopefully doesn't conflict with other codes.
316 if (exit_code == STATUS_GUARD_PAGE_VIOLATION)
317 return 0x1FCF7EC3; // Randomly picked number.
318#endif
319
320 return std::abs(exit_code);
321}
322
[email protected]84c384e2013-03-01 23:20:19323void MarkAppCleanShutdownAndCommit() {
324 PrefService* pref = g_browser_process->local_state();
325 pref->SetBoolean(prefs::kStabilityExitedCleanly, true);
[email protected]6a6d0d12013-10-28 15:58:19326 pref->SetInteger(prefs::kStabilityExecutionPhase,
[email protected]6d67ea0d2013-11-14 11:02:21327 MetricsService::SHUTDOWN_COMPLETE);
[email protected]84c384e2013-03-01 23:20:19328 // Start writing right away (write happens on a different thread).
329 pref->CommitPendingWrite();
330}
331
[email protected]20f999b52012-08-24 22:32:59332} // namespace
initial.commit09911bf2008-07-26 23:55:29333
[email protected]60677562013-11-17 15:52:55334
[email protected]7a5c07812014-02-26 11:45:41335SyntheticTrialGroup::SyntheticTrialGroup(uint32 trial, uint32 group) {
[email protected]60677562013-11-17 15:52:55336 id.name = trial;
337 id.group = group;
338}
339
340SyntheticTrialGroup::~SyntheticTrialGroup() {
341}
342
[email protected]c0c55e92011-09-10 18:47:30343// static
344MetricsService::ShutdownCleanliness MetricsService::clean_shutdown_status_ =
345 MetricsService::CLEANLY_SHUTDOWN;
346
[email protected]6a6d0d12013-10-28 15:58:19347MetricsService::ExecutionPhase MetricsService::execution_phase_ =
[email protected]6d67ea0d2013-11-14 11:02:21348 MetricsService::UNINITIALIZED_PHASE;
[email protected]6a6d0d12013-10-28 15:58:19349
[email protected]679082052010-07-21 21:30:13350// This is used to quickly log stats from child process related notifications in
351// MetricsService::child_stats_buffer_. The buffer's contents are transferred
352// out when Local State is periodically saved. The information is then
353// reported to the UMA server on next launch.
354struct MetricsService::ChildProcessStats {
355 public:
[email protected]f3b357692013-03-22 05:16:13356 explicit ChildProcessStats(int process_type)
[email protected]679082052010-07-21 21:30:13357 : process_launches(0),
358 process_crashes(0),
359 instances(0),
[email protected]cd937072012-07-02 09:00:29360 loading_errors(0),
[email protected]f3b357692013-03-22 05:16:13361 process_type(process_type) {}
[email protected]679082052010-07-21 21:30:13362
363 // This constructor is only used by the map to return some default value for
364 // an index for which no value has been assigned.
365 ChildProcessStats()
366 : process_launches(0),
[email protected]d88bf0a2011-08-30 23:55:57367 process_crashes(0),
368 instances(0),
[email protected]cd937072012-07-02 09:00:29369 loading_errors(0),
[email protected]bd5d6cf2011-12-01 00:39:12370 process_type(content::PROCESS_TYPE_UNKNOWN) {}
[email protected]679082052010-07-21 21:30:13371
372 // The number of times that the given child process has been launched
373 int process_launches;
374
375 // The number of times that the given child process has crashed
376 int process_crashes;
377
378 // The number of instances of this child process that have been created.
379 // An instance is a DOM object rendered by this child process during a page
380 // load.
381 int instances;
382
[email protected]cd937072012-07-02 09:00:29383 // The number of times there was an error loading an instance of this child
384 // process.
385 int loading_errors;
386
[email protected]f3b357692013-03-22 05:16:13387 int process_type;
[email protected]679082052010-07-21 21:30:13388};
initial.commit09911bf2008-07-26 23:55:29389
[email protected]84c988a2011-04-19 17:56:33390// Handles asynchronous fetching of memory details.
391// Will run the provided task after finished.
392class MetricsMemoryDetails : public MemoryDetails {
393 public:
[email protected]2226c222011-11-22 00:08:40394 explicit MetricsMemoryDetails(const base::Closure& callback)
395 : callback_(callback) {}
[email protected]84c988a2011-04-19 17:56:33396
[email protected]b94584a2013-02-07 03:02:08397 virtual void OnDetailsAvailable() OVERRIDE {
[email protected]b3a25092013-05-28 22:08:16398 base::MessageLoop::current()->PostTask(FROM_HERE, callback_);
[email protected]84c988a2011-04-19 17:56:33399 }
400
401 private:
[email protected]b94584a2013-02-07 03:02:08402 virtual ~MetricsMemoryDetails() {}
[email protected]84c988a2011-04-19 17:56:33403
[email protected]2226c222011-11-22 00:08:40404 base::Closure callback_;
[email protected]84c988a2011-04-19 17:56:33405 DISALLOW_COPY_AND_ASSIGN(MetricsMemoryDetails);
406};
407
initial.commit09911bf2008-07-26 23:55:29408// static
[email protected]b1de2c72013-02-06 02:45:47409void MetricsService::RegisterPrefs(PrefRegistrySimple* registry) {
initial.commit09911bf2008-07-26 23:55:29410 DCHECK(IsSingleThreaded());
[email protected]39076642014-05-05 20:32:55411 metrics::MetricsStateManager::RegisterPrefs(registry);
412
[email protected]b1de2c72013-02-06 02:45:47413 registry->RegisterInt64Pref(prefs::kStabilityLaunchTimeSec, 0);
414 registry->RegisterInt64Pref(prefs::kStabilityLastTimestampSec, 0);
[email protected]007b3f82013-04-09 08:46:45415 registry->RegisterStringPref(prefs::kStabilityStatsVersion, std::string());
[email protected]b1de2c72013-02-06 02:45:47416 registry->RegisterInt64Pref(prefs::kStabilityStatsBuildTime, 0);
417 registry->RegisterBooleanPref(prefs::kStabilityExitedCleanly, true);
[email protected]6a6d0d12013-10-28 15:58:19418 registry->RegisterIntegerPref(prefs::kStabilityExecutionPhase,
[email protected]6d67ea0d2013-11-14 11:02:21419 UNINITIALIZED_PHASE);
[email protected]b1de2c72013-02-06 02:45:47420 registry->RegisterBooleanPref(prefs::kStabilitySessionEndCompleted, true);
421 registry->RegisterIntegerPref(prefs::kMetricsSessionID, -1);
422 registry->RegisterIntegerPref(prefs::kStabilityLaunchCount, 0);
423 registry->RegisterIntegerPref(prefs::kStabilityCrashCount, 0);
424 registry->RegisterIntegerPref(prefs::kStabilityIncompleteSessionEndCount, 0);
425 registry->RegisterIntegerPref(prefs::kStabilityPageLoadCount, 0);
426 registry->RegisterIntegerPref(prefs::kStabilityRendererCrashCount, 0);
427 registry->RegisterIntegerPref(prefs::kStabilityExtensionRendererCrashCount,
428 0);
429 registry->RegisterIntegerPref(prefs::kStabilityRendererHangCount, 0);
430 registry->RegisterIntegerPref(prefs::kStabilityChildProcessCrashCount, 0);
431 registry->RegisterIntegerPref(prefs::kStabilityBreakpadRegistrationFail, 0);
432 registry->RegisterIntegerPref(prefs::kStabilityBreakpadRegistrationSuccess,
433 0);
434 registry->RegisterIntegerPref(prefs::kStabilityDebuggerPresent, 0);
435 registry->RegisterIntegerPref(prefs::kStabilityDebuggerNotPresent, 0);
[email protected]c1834a92011-01-21 18:21:03436#if defined(OS_CHROMEOS)
[email protected]b1de2c72013-02-06 02:45:47437 registry->RegisterIntegerPref(prefs::kStabilityOtherUserCrashCount, 0);
438 registry->RegisterIntegerPref(prefs::kStabilityKernelCrashCount, 0);
439 registry->RegisterIntegerPref(prefs::kStabilitySystemUncleanShutdownCount, 0);
[email protected]c1834a92011-01-21 18:21:03440#endif // OS_CHROMEOS
[email protected]e73c01972008-08-13 00:18:24441
[email protected]0f2f7792013-11-28 16:09:14442 registry->RegisterStringPref(prefs::kStabilitySavedSystemProfile,
443 std::string());
444 registry->RegisterStringPref(prefs::kStabilitySavedSystemProfileHash,
445 std::string());
446
[email protected]7f07db62014-05-15 01:12:45447 registry->RegisterListPref(metrics::prefs::kMetricsInitialLogs);
448 registry->RegisterListPref(metrics::prefs::kMetricsOngoingLogs);
[email protected]0bb1a622009-03-04 03:22:32449
[email protected]5c181552013-02-07 09:12:52450 registry->RegisterInt64Pref(prefs::kInstallDate, 0);
[email protected]b1de2c72013-02-06 02:45:47451 registry->RegisterInt64Pref(prefs::kUninstallMetricsPageLoadCount, 0);
452 registry->RegisterInt64Pref(prefs::kUninstallLaunchCount, 0);
[email protected]b1de2c72013-02-06 02:45:47453 registry->RegisterInt64Pref(prefs::kUninstallMetricsUptimeSec, 0);
454 registry->RegisterInt64Pref(prefs::kUninstallLastLaunchTimeSec, 0);
455 registry->RegisterInt64Pref(prefs::kUninstallLastObservedRunTimeSec, 0);
[email protected]c778687a2014-02-11 14:46:45456
457#if defined(OS_ANDROID)
458 RegisterPrefsAndroid(registry);
459#endif // defined(OS_ANDROID)
initial.commit09911bf2008-07-26 23:55:29460}
461
[email protected]c3cac952014-05-09 01:51:18462MetricsService::MetricsService(metrics::MetricsStateManager* state_manager)
[email protected]7f07db62014-05-15 01:12:45463 : MetricsServiceBase(g_browser_process->local_state(),
464 kUploadLogAvoidRetransmitSize),
465 state_manager_(state_manager),
[email protected]37d4709a2014-03-29 03:07:40466 recording_active_(false),
[email protected]d01b8732008-10-16 02:18:07467 reporting_active_(false),
[email protected]410938e02012-10-24 16:33:59468 test_mode_active_(false),
[email protected]d01b8732008-10-16 02:18:07469 state_(INITIALIZED),
[email protected]80a8f312013-12-16 18:00:30470 has_initial_stability_log_(false),
[email protected]d01b8732008-10-16 02:18:07471 idle_since_last_transmission_(false),
[email protected]80a8f312013-12-16 18:00:30472 session_id_(-1),
initial.commit09911bf2008-07-26 23:55:29473 next_window_id_(0),
[email protected]9c009092013-05-01 03:14:09474 self_ptr_factory_(this),
475 state_saver_factory_(this),
[email protected]e5354322012-08-09 23:07:37476 waiting_for_asynchronous_reporting_step_(false),
[email protected]39076642014-05-05 20:32:55477 num_async_histogram_fetches_in_progress_(0) {
initial.commit09911bf2008-07-26 23:55:29478 DCHECK(IsSingleThreaded());
[email protected]39076642014-05-05 20:32:55479 DCHECK(state_manager_);
[email protected]7f7f1962011-04-20 15:58:16480
[email protected]f4eaf7b92013-02-28 22:00:40481 BrowserChildProcessObserver::Add(this);
initial.commit09911bf2008-07-26 23:55:29482}
483
484MetricsService::~MetricsService() {
[email protected]410938e02012-10-24 16:33:59485 DisableRecording();
[email protected]f4eaf7b92013-02-28 22:00:40486
487 BrowserChildProcessObserver::Remove(this);
initial.commit09911bf2008-07-26 23:55:29488}
489
[email protected]39076642014-05-05 20:32:55490void MetricsService::InitializeMetricsRecordingState() {
491 InitializeMetricsState();
[email protected]80a8f312013-12-16 18:00:30492
493 base::Closure callback = base::Bind(&MetricsService::StartScheduledUpload,
494 self_ptr_factory_.GetWeakPtr());
495 scheduler_.reset(new MetricsReportingScheduler(callback));
496}
497
[email protected]d01b8732008-10-16 02:18:07498void MetricsService::Start() {
[email protected]b1c8dc02011-04-13 18:32:04499 HandleIdleSinceLastTransmission(false);
[email protected]410938e02012-10-24 16:33:59500 EnableRecording();
501 EnableReporting();
[email protected]d01b8732008-10-16 02:18:07502}
503
[email protected]39076642014-05-05 20:32:55504bool MetricsService::StartIfMetricsReportingEnabled() {
505 const bool enabled = state_manager_->IsMetricsReportingEnabled();
506 if (enabled)
507 Start();
508 return enabled;
509}
510
[email protected]410938e02012-10-24 16:33:59511void MetricsService::StartRecordingForTests() {
512 test_mode_active_ = true;
513 EnableRecording();
514 DisableReporting();
[email protected]d01b8732008-10-16 02:18:07515}
516
517void MetricsService::Stop() {
[email protected]b1c8dc02011-04-13 18:32:04518 HandleIdleSinceLastTransmission(false);
[email protected]410938e02012-10-24 16:33:59519 DisableReporting();
520 DisableRecording();
521}
522
523void MetricsService::EnableReporting() {
524 if (reporting_active_)
525 return;
526 reporting_active_ = true;
527 StartSchedulerIfNecessary();
528}
529
530void MetricsService::DisableReporting() {
531 reporting_active_ = false;
[email protected]d01b8732008-10-16 02:18:07532}
533
[email protected]edafd4c2011-05-10 17:18:53534std::string MetricsService::GetClientId() {
[email protected]39076642014-05-05 20:32:55535 return state_manager_->client_id();
[email protected]edafd4c2011-05-10 17:18:53536}
537
[email protected]20f999b52012-08-24 22:32:59538scoped_ptr<const base::FieldTrial::EntropyProvider>
[email protected]39076642014-05-05 20:32:55539MetricsService::CreateEntropyProvider() {
540 // TODO(asvitkine): Refactor the code so that MetricsService does not expose
541 // this method.
542 return state_manager_->CreateEntropyProvider();
[email protected]5cbeeef72012-02-08 02:05:18543}
544
[email protected]410938e02012-10-24 16:33:59545void MetricsService::EnableRecording() {
initial.commit09911bf2008-07-26 23:55:29546 DCHECK(IsSingleThreaded());
547
[email protected]410938e02012-10-24 16:33:59548 if (recording_active_)
initial.commit09911bf2008-07-26 23:55:29549 return;
[email protected]410938e02012-10-24 16:33:59550 recording_active_ = true;
initial.commit09911bf2008-07-26 23:55:29551
[email protected]39076642014-05-05 20:32:55552 state_manager_->ForceClientIdCreation();
553 crash_keys::SetClientID(state_manager_->client_id());
[email protected]410938e02012-10-24 16:33:59554 if (!log_manager_.current_log())
555 OpenNewLog();
[email protected]005ef3e2009-05-22 20:55:46556
[email protected]410938e02012-10-24 16:33:59557 SetUpNotifications(&registrar_, this);
[email protected]e6e30ac2014-01-13 21:24:39558 base::RemoveActionCallback(action_callback_);
[email protected]dd98f392013-02-04 13:03:22559 action_callback_ = base::Bind(&MetricsService::OnUserAction,
560 base::Unretained(this));
[email protected]e6e30ac2014-01-13 21:24:39561 base::AddActionCallback(action_callback_);
[email protected]410938e02012-10-24 16:33:59562}
563
564void MetricsService::DisableRecording() {
565 DCHECK(IsSingleThreaded());
566
567 if (!recording_active_)
568 return;
569 recording_active_ = false;
570
[email protected]e6e30ac2014-01-13 21:24:39571 base::RemoveActionCallback(action_callback_);
[email protected]410938e02012-10-24 16:33:59572 registrar_.RemoveAll();
573 PushPendingLogsToPersistentStorage();
574 DCHECK(!log_manager_.has_staged_log());
initial.commit09911bf2008-07-26 23:55:29575}
576
[email protected]d01b8732008-10-16 02:18:07577bool MetricsService::recording_active() const {
initial.commit09911bf2008-07-26 23:55:29578 DCHECK(IsSingleThreaded());
[email protected]d01b8732008-10-16 02:18:07579 return recording_active_;
initial.commit09911bf2008-07-26 23:55:29580}
581
[email protected]d01b8732008-10-16 02:18:07582bool MetricsService::reporting_active() const {
583 DCHECK(IsSingleThreaded());
584 return reporting_active_;
initial.commit09911bf2008-07-26 23:55:29585}
586
[email protected]87ef9ea2011-02-26 03:15:15587// static
[email protected]6c2381d2011-10-19 02:52:53588void MetricsService::SetUpNotifications(
589 content::NotificationRegistrar* registrar,
590 content::NotificationObserver* observer) {
591 registrar->Add(observer, chrome::NOTIFICATION_BROWSER_OPENED,
[email protected]ad50def52011-10-19 23:17:07592 content::NotificationService::AllBrowserContextsAndSources());
[email protected]6c2381d2011-10-19 02:52:53593 registrar->Add(observer, chrome::NOTIFICATION_BROWSER_CLOSED,
[email protected]ad50def52011-10-19 23:17:07594 content::NotificationService::AllSources());
[email protected]884033e2012-04-16 19:38:42595 registrar->Add(observer, chrome::NOTIFICATION_TAB_PARENTED,
[email protected]ad50def52011-10-19 23:17:07596 content::NotificationService::AllSources());
[email protected]884033e2012-04-16 19:38:42597 registrar->Add(observer, chrome::NOTIFICATION_TAB_CLOSING,
[email protected]ad50def52011-10-19 23:17:07598 content::NotificationService::AllSources());
[email protected]6c2381d2011-10-19 02:52:53599 registrar->Add(observer, content::NOTIFICATION_LOAD_START,
[email protected]ad50def52011-10-19 23:17:07600 content::NotificationService::AllSources());
[email protected]6c2381d2011-10-19 02:52:53601 registrar->Add(observer, content::NOTIFICATION_LOAD_STOP,
[email protected]ad50def52011-10-19 23:17:07602 content::NotificationService::AllSources());
[email protected]6c2381d2011-10-19 02:52:53603 registrar->Add(observer, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
[email protected]ad50def52011-10-19 23:17:07604 content::NotificationService::AllSources());
[email protected]42d8d7582013-11-09 01:24:38605 registrar->Add(observer, content::NOTIFICATION_RENDER_WIDGET_HOST_HANG,
[email protected]ad50def52011-10-19 23:17:07606 content::NotificationService::AllSources());
[email protected]6c2381d2011-10-19 02:52:53607 registrar->Add(observer, chrome::NOTIFICATION_OMNIBOX_OPENED_URL,
[email protected]ad50def52011-10-19 23:17:07608 content::NotificationService::AllSources());
[email protected]87ef9ea2011-02-26 03:15:15609}
610
[email protected]f4eaf7b92013-02-28 22:00:40611void MetricsService::BrowserChildProcessHostConnected(
612 const content::ChildProcessData& data) {
613 GetChildProcessStats(data).process_launches++;
614}
615
616void MetricsService::BrowserChildProcessCrashed(
617 const content::ChildProcessData& data) {
618 GetChildProcessStats(data).process_crashes++;
619 // Exclude plugin crashes from the count below because we report them via
620 // a separate UMA metric.
[email protected]f3b357692013-03-22 05:16:13621 if (!IsPluginProcess(data.process_type))
[email protected]f4eaf7b92013-02-28 22:00:40622 IncrementPrefValue(prefs::kStabilityChildProcessCrashCount);
623}
624
625void MetricsService::BrowserChildProcessInstanceCreated(
626 const content::ChildProcessData& data) {
627 GetChildProcessStats(data).instances++;
628}
629
[email protected]432115822011-07-10 15:52:27630void MetricsService::Observe(int type,
[email protected]6c2381d2011-10-19 02:52:53631 const content::NotificationSource& source,
632 const content::NotificationDetails& details) {
[email protected]cac267c2011-09-29 15:18:10633 DCHECK(log_manager_.current_log());
initial.commit09911bf2008-07-26 23:55:29634 DCHECK(IsSingleThreaded());
635
[email protected]e5ad60a2014-03-11 03:54:04636 // Check for notifications related to core stability metrics, or that are
637 // just triggers to end idle mode. Anything else should be added in the later
638 // switch statement, where they take effect only if general metrics should be
639 // logged.
640 bool handled = false;
[email protected]432115822011-07-10 15:52:27641 switch (type) {
[email protected]432115822011-07-10 15:52:27642 case chrome::NOTIFICATION_BROWSER_OPENED:
[email protected]46a0efc2013-07-17 15:40:47643 case chrome::NOTIFICATION_BROWSER_CLOSED:
644 case chrome::NOTIFICATION_TAB_PARENTED:
645 case chrome::NOTIFICATION_TAB_CLOSING:
[email protected]432115822011-07-10 15:52:27646 case content::NOTIFICATION_LOAD_STOP:
[email protected]e5ad60a2014-03-11 03:54:04647 // These notifications are used only to break out of idle mode.
648 handled = true;
initial.commit09911bf2008-07-26 23:55:29649 break;
650
[email protected]752a5262013-06-23 14:53:42651 case content::NOTIFICATION_LOAD_START: {
652 content::NavigationController* controller =
653 content::Source<content::NavigationController>(source).ptr();
654 content::WebContents* web_contents = controller->GetWebContents();
655 LogLoadStarted(web_contents);
[email protected]e5ad60a2014-03-11 03:54:04656 handled = true;
initial.commit09911bf2008-07-26 23:55:29657 break;
[email protected]752a5262013-06-23 14:53:42658 }
initial.commit09911bf2008-07-26 23:55:29659
[email protected]432115822011-07-10 15:52:27660 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: {
[email protected]e5ad60a2014-03-11 03:54:04661 content::RenderProcessHost::RendererClosedDetails* process_details =
662 content::Details<
663 content::RenderProcessHost::RendererClosedDetails>(
664 details).ptr();
665 content::RenderProcessHost* host =
666 content::Source<content::RenderProcessHost>(source).ptr();
667 LogRendererCrash(
668 host, process_details->status, process_details->exit_code);
669 handled = true;
initial.commit09911bf2008-07-26 23:55:29670 break;
[email protected]1226abb2010-06-10 18:01:28671 }
initial.commit09911bf2008-07-26 23:55:29672
[email protected]e5ad60a2014-03-11 03:54:04673 case content::NOTIFICATION_RENDER_WIDGET_HOST_HANG:
674 LogRendererHang();
675 handled = true;
initial.commit09911bf2008-07-26 23:55:29676 break;
[email protected]e5ad60a2014-03-11 03:54:04677
678 default:
679 // Everything else is handled after the early return check below.
680 break;
681 }
682
683 // If it wasn't one of the stability-related notifications, and event
684 // logging isn't suppressed, handle it.
685 if (!handled && ShouldLogEvents()) {
686 switch (type) {
687 case chrome::NOTIFICATION_OMNIBOX_OPENED_URL: {
688 MetricsLog* current_log =
689 static_cast<MetricsLog*>(log_manager_.current_log());
690 DCHECK(current_log);
691 current_log->RecordOmniboxOpenedURL(
692 *content::Details<OmniboxLog>(details).ptr());
693 break;
694 }
695
696 default:
697 NOTREACHED();
698 break;
699 }
initial.commit09911bf2008-07-26 23:55:29700 }
[email protected]d01b8732008-10-16 02:18:07701
702 HandleIdleSinceLastTransmission(false);
[email protected]d01b8732008-10-16 02:18:07703}
704
705void MetricsService::HandleIdleSinceLastTransmission(bool in_idle) {
706 // If there wasn't a lot of action, maybe the computer was asleep, in which
707 // case, the log transmissions should have stopped. Here we start them up
708 // again.
[email protected]cac78842008-11-27 01:02:20709 if (!in_idle && idle_since_last_transmission_)
[email protected]7f7f1962011-04-20 15:58:16710 StartSchedulerIfNecessary();
[email protected]cac78842008-11-27 01:02:20711 idle_since_last_transmission_ = in_idle;
initial.commit09911bf2008-07-26 23:55:29712}
713
initial.commit09911bf2008-07-26 23:55:29714void MetricsService::RecordStartOfSessionEnd() {
[email protected]466f3c12011-03-23 21:20:38715 LogCleanShutdown();
initial.commit09911bf2008-07-26 23:55:29716 RecordBooleanPrefValue(prefs::kStabilitySessionEndCompleted, false);
717}
718
719void MetricsService::RecordCompletedSessionEnd() {
[email protected]466f3c12011-03-23 21:20:38720 LogCleanShutdown();
initial.commit09911bf2008-07-26 23:55:29721 RecordBooleanPrefValue(prefs::kStabilitySessionEndCompleted, true);
722}
723
[email protected]410938e02012-10-24 16:33:59724#if defined(OS_ANDROID) || defined(OS_IOS)
[email protected]117fbdf22012-06-26 18:36:39725void MetricsService::OnAppEnterBackground() {
726 scheduler_->Stop();
727
[email protected]84c384e2013-03-01 23:20:19728 MarkAppCleanShutdownAndCommit();
[email protected]117fbdf22012-06-26 18:36:39729
730 // At this point, there's no way of knowing when the process will be
731 // killed, so this has to be treated similar to a shutdown, closing and
732 // persisting all logs. Unlinke a shutdown, the state is primed to be ready
733 // to continue logging and uploading if the process does return.
[email protected]80a8f312013-12-16 18:00:30734 if (recording_active() && state_ >= SENDING_INITIAL_STABILITY_LOG) {
[email protected]117fbdf22012-06-26 18:36:39735 PushPendingLogsToPersistentStorage();
[email protected]410938e02012-10-24 16:33:59736 // Persisting logs closes the current log, so start recording a new log
737 // immediately to capture any background work that might be done before the
738 // process is killed.
739 OpenNewLog();
[email protected]117fbdf22012-06-26 18:36:39740 }
[email protected]117fbdf22012-06-26 18:36:39741}
742
743void MetricsService::OnAppEnterForeground() {
744 PrefService* pref = g_browser_process->local_state();
745 pref->SetBoolean(prefs::kStabilityExitedCleanly, false);
746
747 StartSchedulerIfNecessary();
748}
[email protected]84c384e2013-03-01 23:20:19749#else
750void MetricsService::LogNeedForCleanShutdown() {
751 PrefService* pref = g_browser_process->local_state();
752 pref->SetBoolean(prefs::kStabilityExitedCleanly, false);
753 // Redundant setting to be sure we call for a clean shutdown.
754 clean_shutdown_status_ = NEED_TO_SHUTDOWN;
755}
756#endif // defined(OS_ANDROID) || defined(OS_IOS)
[email protected]117fbdf22012-06-26 18:36:39757
[email protected]6d67ea0d2013-11-14 11:02:21758// static
759void MetricsService::SetExecutionPhase(ExecutionPhase execution_phase) {
760 execution_phase_ = execution_phase;
761 PrefService* pref = g_browser_process->local_state();
762 pref->SetInteger(prefs::kStabilityExecutionPhase, execution_phase_);
763}
764
[email protected]7f7f1962011-04-20 15:58:16765void MetricsService::RecordBreakpadRegistration(bool success) {
[email protected]68475e602008-08-22 03:21:15766 if (!success)
[email protected]e73c01972008-08-13 00:18:24767 IncrementPrefValue(prefs::kStabilityBreakpadRegistrationFail);
768 else
769 IncrementPrefValue(prefs::kStabilityBreakpadRegistrationSuccess);
770}
771
772void MetricsService::RecordBreakpadHasDebugger(bool has_debugger) {
773 if (!has_debugger)
774 IncrementPrefValue(prefs::kStabilityDebuggerNotPresent);
775 else
[email protected]68475e602008-08-22 03:21:15776 IncrementPrefValue(prefs::kStabilityDebuggerPresent);
[email protected]e73c01972008-08-13 00:18:24777}
778
[email protected]261ab7c2013-08-19 15:04:58779#if defined(OS_WIN)
780void MetricsService::CountBrowserCrashDumpAttempts() {
[email protected]a5e0fe5e2013-09-16 06:15:45781 // Open the registry key for iteration.
[email protected]261ab7c2013-08-19 15:04:58782 base::win::RegKey regkey;
783 if (regkey.Open(HKEY_CURRENT_USER,
[email protected]a5e0fe5e2013-09-16 06:15:45784 chrome::kBrowserCrashDumpAttemptsRegistryPath,
[email protected]261ab7c2013-08-19 15:04:58785 KEY_ALL_ACCESS) != ERROR_SUCCESS) {
786 return;
787 }
788
[email protected]a5e0fe5e2013-09-16 06:15:45789 // The values we're interested in counting are all prefixed with the version.
790 base::string16 chrome_version(base::ASCIIToUTF16(chrome::kChromeVersion));
791
792 // Track a list of values to delete. We don't modify the registry key while
793 // we're iterating over its values.
794 typedef std::vector<base::string16> StringVector;
795 StringVector to_delete;
796
797 // Iterate over the values in the key counting dumps with and without crashes.
798 // We directly walk the values instead of using RegistryValueIterator in order
799 // to read all of the values as DWORDS instead of strings.
800 base::string16 name;
801 DWORD value = 0;
802 int dumps_with_crash = 0;
803 int dumps_with_no_crash = 0;
[email protected]261ab7c2013-08-19 15:04:58804 for (int i = regkey.GetValueCount() - 1; i >= 0; --i) {
[email protected]a5e0fe5e2013-09-16 06:15:45805 if (regkey.GetValueNameAt(i, &name) == ERROR_SUCCESS &&
806 StartsWith(name, chrome_version, false) &&
807 regkey.ReadValueDW(name.c_str(), &value) == ERROR_SUCCESS) {
808 to_delete.push_back(name);
809 if (value == 0)
810 ++dumps_with_no_crash;
811 else
812 ++dumps_with_crash;
[email protected]261ab7c2013-08-19 15:04:58813 }
814 }
[email protected]a5e0fe5e2013-09-16 06:15:45815
816 // Delete the registry keys we've just counted.
817 for (StringVector::iterator i = to_delete.begin(); i != to_delete.end(); ++i)
818 regkey.DeleteValue(i->c_str());
819
820 // Capture the histogram samples.
821 if (dumps_with_crash != 0)
822 UMA_HISTOGRAM_COUNTS("Chrome.BrowserDumpsWithCrash", dumps_with_crash);
823 if (dumps_with_no_crash != 0)
824 UMA_HISTOGRAM_COUNTS("Chrome.BrowserDumpsWithNoCrash", dumps_with_no_crash);
825 int total_dumps = dumps_with_crash + dumps_with_no_crash;
826 if (total_dumps != 0)
827 UMA_HISTOGRAM_COUNTS("Chrome.BrowserCrashDumpAttempts", total_dumps);
[email protected]261ab7c2013-08-19 15:04:58828}
829#endif // defined(OS_WIN)
830
initial.commit09911bf2008-07-26 23:55:29831//------------------------------------------------------------------------------
832// private methods
833//------------------------------------------------------------------------------
834
835
836//------------------------------------------------------------------------------
837// Initialization methods
838
[email protected]39076642014-05-05 20:32:55839void MetricsService::InitializeMetricsState() {
[email protected]79bf0b72009-04-27 21:30:55840#if defined(OS_POSIX)
[email protected]b4a72d842012-03-22 20:09:09841 network_stats_server_ = chrome_common_net::kEchoTestServerLocation;
842 http_pipelining_test_server_ = chrome_common_net::kPipelineTestServerBaseUrl;
[email protected]79bf0b72009-04-27 21:30:55843#else
844 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
[email protected]d67d1052011-06-09 05:11:41845 network_stats_server_ = dist->GetNetworkStatsServer();
[email protected]adbb3762012-03-09 22:20:08846 http_pipelining_test_server_ = dist->GetHttpPipeliningTestServer();
[email protected]79bf0b72009-04-27 21:30:55847#endif
848
initial.commit09911bf2008-07-26 23:55:29849 PrefService* pref = g_browser_process->local_state();
850 DCHECK(pref);
851
[email protected]b58b8b22014-04-08 22:40:33852 pref->SetString(prefs::kStabilityStatsVersion,
853 MetricsLog::GetVersionString());
854 pref->SetInt64(prefs::kStabilityStatsBuildTime, MetricsLog::GetBuildTime());
[email protected]541f77922009-02-23 21:14:38855
initial.commit09911bf2008-07-26 23:55:29856 session_id_ = pref->GetInteger(prefs::kMetricsSessionID);
initial.commit09911bf2008-07-26 23:55:29857
[email protected]c778687a2014-02-11 14:46:45858#if defined(OS_ANDROID)
859 LogAndroidStabilityToPrefs(pref);
860#endif // defined(OS_ANDROID)
861
[email protected]e73c01972008-08-13 00:18:24862 if (!pref->GetBoolean(prefs::kStabilityExitedCleanly)) {
863 IncrementPrefValue(prefs::kStabilityCrashCount);
[email protected]c0c55e92011-09-10 18:47:30864 // Reset flag, and wait until we call LogNeedForCleanShutdown() before
865 // monitoring.
866 pref->SetBoolean(prefs::kStabilityExitedCleanly, true);
[email protected]6a6d0d12013-10-28 15:58:19867
868 // TODO(rtenneti): On windows, consider saving/getting execution_phase from
869 // the registry.
870 int execution_phase = pref->GetInteger(prefs::kStabilityExecutionPhase);
[email protected]6d67ea0d2013-11-14 11:02:21871 UMA_HISTOGRAM_SPARSE_SLOWLY("Chrome.Browser.CrashedExecutionPhase",
[email protected]6a6d0d12013-10-28 15:58:19872 execution_phase);
[email protected]80a8f312013-12-16 18:00:30873
874 // If the previous session didn't exit cleanly, then prepare an initial
875 // stability log if UMA is enabled.
[email protected]39076642014-05-05 20:32:55876 if (state_manager_->IsMetricsReportingEnabled())
[email protected]80a8f312013-12-16 18:00:30877 PrepareInitialStabilityLog();
initial.commit09911bf2008-07-26 23:55:29878 }
[email protected]80a8f312013-12-16 18:00:30879
880 // Update session ID.
881 ++session_id_;
882 pref->SetInteger(prefs::kMetricsSessionID, session_id_);
883
884 // Stability bookkeeping
885 IncrementPrefValue(prefs::kStabilityLaunchCount);
886
[email protected]6d67ea0d2013-11-14 11:02:21887 DCHECK_EQ(UNINITIALIZED_PHASE, execution_phase_);
888 SetExecutionPhase(START_METRICS_RECORDING);
[email protected]e73c01972008-08-13 00:18:24889
[email protected]261ab7c2013-08-19 15:04:58890#if defined(OS_WIN)
891 CountBrowserCrashDumpAttempts();
892#endif // defined(OS_WIN)
893
[email protected]e73c01972008-08-13 00:18:24894 if (!pref->GetBoolean(prefs::kStabilitySessionEndCompleted)) {
895 IncrementPrefValue(prefs::kStabilityIncompleteSessionEndCount);
[email protected]c9abf242009-07-18 06:00:38896 // This is marked false when we get a WM_ENDSESSION.
897 pref->SetBoolean(prefs::kStabilitySessionEndCompleted, true);
initial.commit09911bf2008-07-26 23:55:29898 }
initial.commit09911bf2008-07-26 23:55:29899
[email protected]076961c2014-03-12 22:23:56900 // Call GetUptimes() for the first time, thus allowing all later calls
901 // to record incremental uptimes accurately.
902 base::TimeDelta ignored_uptime_parameter;
903 base::TimeDelta startup_uptime;
904 GetUptimes(pref, &startup_uptime, &ignored_uptime_parameter);
[email protected]c68a2b9b2013-10-09 18:16:36905 DCHECK_EQ(0, startup_uptime.InMicroseconds());
[email protected]9165f742010-03-10 22:55:01906 // For backwards compatibility, leave this intact in case Omaha is checking
907 // them. prefs::kStabilityLastTimestampSec may also be useless now.
908 // TODO(jar): Delete these if they have no uses.
[email protected]0bb1a622009-03-04 03:22:32909 pref->SetInt64(prefs::kStabilityLaunchTimeSec, Time::Now().ToTimeT());
910
911 // Bookkeeping for the uninstall metrics.
912 IncrementLongPrefsValue(prefs::kUninstallLaunchCount);
initial.commit09911bf2008-07-26 23:55:29913
[email protected]92745242009-06-12 16:52:21914 // Get stats on use of command line.
915 const CommandLine* command_line(CommandLine::ForCurrentProcess());
916 size_t common_commands = 0;
917 if (command_line->HasSwitch(switches::kUserDataDir)) {
918 ++common_commands;
919 UMA_HISTOGRAM_COUNTS_100("Chrome.CommandLineDatDirCount", 1);
920 }
921
922 if (command_line->HasSwitch(switches::kApp)) {
923 ++common_commands;
924 UMA_HISTOGRAM_COUNTS_100("Chrome.CommandLineAppModeCount", 1);
925 }
926
[email protected]62b4e522011-07-13 21:46:32927 size_t switch_count = command_line->GetSwitches().size();
928 UMA_HISTOGRAM_COUNTS_100("Chrome.CommandLineFlagCount", switch_count);
[email protected]92745242009-06-12 16:52:21929 UMA_HISTOGRAM_COUNTS_100("Chrome.CommandLineUncommonFlagCount",
[email protected]62b4e522011-07-13 21:46:32930 switch_count - common_commands);
[email protected]92745242009-06-12 16:52:21931
initial.commit09911bf2008-07-26 23:55:29932 // Kick off the process of saving the state (so the uptime numbers keep
933 // getting updated) every n minutes.
934 ScheduleNextStateSave();
935}
936
[email protected]c94d7382012-02-28 08:43:40937// static
[email protected]d33e7cc2011-09-23 01:43:56938void MetricsService::InitTaskGetHardwareClass(
[email protected]c94d7382012-02-28 08:43:40939 base::WeakPtr<MetricsService> self,
[email protected]d33e7cc2011-09-23 01:43:56940 base::MessageLoopProxy* target_loop) {
[email protected]d33e7cc2011-09-23 01:43:56941 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
942
943 std::string hardware_class;
944#if defined(OS_CHROMEOS)
945 chromeos::system::StatisticsProvider::GetInstance()->GetMachineStatistic(
946 "hardware_class", &hardware_class);
947#endif // OS_CHROMEOS
948
949 target_loop->PostTask(FROM_HERE,
950 base::Bind(&MetricsService::OnInitTaskGotHardwareClass,
[email protected]c94d7382012-02-28 08:43:40951 self, hardware_class));
[email protected]d33e7cc2011-09-23 01:43:56952}
953
954void MetricsService::OnInitTaskGotHardwareClass(
955 const std::string& hardware_class) {
[email protected]ed0fd002012-04-25 23:10:34956 DCHECK_EQ(INIT_TASK_SCHEDULED, state_);
[email protected]85ed9d42010-06-08 22:37:44957 hardware_class_ = hardware_class;
[email protected]d33e7cc2011-09-23 01:43:56958
[email protected]ebd71962012-12-20 02:56:55959#if defined(ENABLE_PLUGINS)
[email protected]d33e7cc2011-09-23 01:43:56960 // Start the next part of the init task: loading plugin information.
961 PluginService::GetInstance()->GetPlugins(
962 base::Bind(&MetricsService::OnInitTaskGotPluginInfo,
[email protected]c94d7382012-02-28 08:43:40963 self_ptr_factory_.GetWeakPtr()));
[email protected]ebd71962012-12-20 02:56:55964#else
[email protected]d7bd3e52013-07-21 04:29:20965 std::vector<content::WebPluginInfo> plugin_list_empty;
[email protected]ebd71962012-12-20 02:56:55966 OnInitTaskGotPluginInfo(plugin_list_empty);
967#endif // defined(ENABLE_PLUGINS)
[email protected]d33e7cc2011-09-23 01:43:56968}
969
970void MetricsService::OnInitTaskGotPluginInfo(
[email protected]d7bd3e52013-07-21 04:29:20971 const std::vector<content::WebPluginInfo>& plugins) {
[email protected]ed0fd002012-04-25 23:10:34972 DCHECK_EQ(INIT_TASK_SCHEDULED, state_);
[email protected]35fa6a22009-08-15 00:04:01973 plugins_ = plugins;
[email protected]d33e7cc2011-09-23 01:43:56974
[email protected]197c0772012-05-14 23:50:51975 // Schedules a task on a blocking pool thread to gather Google Update
976 // statistics (requires Registry reads).
977 BrowserThread::PostBlockingPoolTask(
978 FROM_HERE,
979 base::Bind(&MetricsService::InitTaskGetGoogleUpdateData,
980 self_ptr_factory_.GetWeakPtr(),
[email protected]b3a25092013-05-28 22:08:16981 base::MessageLoop::current()->message_loop_proxy()));
[email protected]197c0772012-05-14 23:50:51982}
983
984// static
985void MetricsService::InitTaskGetGoogleUpdateData(
986 base::WeakPtr<MetricsService> self,
987 base::MessageLoopProxy* target_loop) {
988 GoogleUpdateMetrics google_update_metrics;
989
990#if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
991 const bool system_install = GoogleUpdateSettings::IsSystemInstall();
992
993 google_update_metrics.is_system_install = system_install;
994 google_update_metrics.last_started_au =
995 GoogleUpdateSettings::GetGoogleUpdateLastStartedAU(system_install);
996 google_update_metrics.last_checked =
997 GoogleUpdateSettings::GetGoogleUpdateLastChecked(system_install);
998 GoogleUpdateSettings::GetUpdateDetailForGoogleUpdate(
999 system_install,
1000 &google_update_metrics.google_update_data);
1001 GoogleUpdateSettings::GetUpdateDetail(
1002 system_install,
1003 &google_update_metrics.product_data);
1004#endif // defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
1005
1006 target_loop->PostTask(FROM_HERE,
1007 base::Bind(&MetricsService::OnInitTaskGotGoogleUpdateData,
1008 self, google_update_metrics));
1009}
1010
1011void MetricsService::OnInitTaskGotGoogleUpdateData(
1012 const GoogleUpdateMetrics& google_update_metrics) {
1013 DCHECK_EQ(INIT_TASK_SCHEDULED, state_);
1014
1015 google_update_metrics_ = google_update_metrics;
1016
[email protected]ed0fd002012-04-25 23:10:341017 // Start the next part of the init task: fetching performance data. This will
1018 // call into |FinishedReceivingProfilerData()| when the task completes.
1019 chrome_browser_metrics::TrackingSynchronizer::FetchProfilerDataAsynchronously(
1020 self_ptr_factory_.GetWeakPtr());
1021}
1022
[email protected]dd98f392013-02-04 13:03:221023void MetricsService::OnUserAction(const std::string& action) {
[email protected]e5ad60a2014-03-11 03:54:041024 if (!ShouldLogEvents())
[email protected]dd98f392013-02-04 13:03:221025 return;
1026
[email protected]4426d2d2014-04-09 12:33:001027 log_manager_.current_log()->RecordUserAction(action);
[email protected]dd98f392013-02-04 13:03:221028 HandleIdleSinceLastTransmission(false);
1029}
1030
[email protected]ed0fd002012-04-25 23:10:341031void MetricsService::ReceivedProfilerData(
1032 const tracked_objects::ProcessDataSnapshot& process_data,
[email protected]f3b357692013-03-22 05:16:131033 int process_type) {
[email protected]ed0fd002012-04-25 23:10:341034 DCHECK_EQ(INIT_TASK_SCHEDULED, state_);
1035
1036 // Upon the first callback, create the initial log so that we can immediately
1037 // save the profiler data.
[email protected]9eae4032014-04-09 19:15:191038 if (!initial_metrics_log_.get()) {
1039 initial_metrics_log_.reset(
[email protected]39076642014-05-05 20:32:551040 new MetricsLog(state_manager_->client_id(), session_id_,
1041 MetricsLog::ONGOING_LOG));
[email protected]2a321de32014-05-10 19:59:061042 NotifyOnDidCreateMetricsLog();
[email protected]9eae4032014-04-09 19:15:191043 }
[email protected]ed0fd002012-04-25 23:10:341044
[email protected]80a8f312013-12-16 18:00:301045 initial_metrics_log_->RecordProfilerData(process_data, process_type);
[email protected]ed0fd002012-04-25 23:10:341046}
1047
1048void MetricsService::FinishedReceivingProfilerData() {
1049 DCHECK_EQ(INIT_TASK_SCHEDULED, state_);
[email protected]c68a2b9b2013-10-09 18:16:361050 state_ = INIT_TASK_DONE;
[email protected]70886cd2013-12-04 05:53:421051 scheduler_->InitTaskComplete();
[email protected]c68a2b9b2013-10-09 18:16:361052}
1053
[email protected]076961c2014-03-12 22:23:561054void MetricsService::GetUptimes(PrefService* pref,
1055 base::TimeDelta* incremental_uptime,
1056 base::TimeDelta* uptime) {
[email protected]c68a2b9b2013-10-09 18:16:361057 base::TimeTicks now = base::TimeTicks::Now();
[email protected]076961c2014-03-12 22:23:561058 // If this is the first call, init |first_updated_time_| and
1059 // |last_updated_time_|.
1060 if (last_updated_time_.is_null()) {
1061 first_updated_time_ = now;
[email protected]c68a2b9b2013-10-09 18:16:361062 last_updated_time_ = now;
[email protected]076961c2014-03-12 22:23:561063 }
1064 *incremental_uptime = now - last_updated_time_;
1065 *uptime = now - first_updated_time_;
[email protected]c68a2b9b2013-10-09 18:16:361066 last_updated_time_ = now;
1067
[email protected]076961c2014-03-12 22:23:561068 const int64 incremental_time_secs = incremental_uptime->InSeconds();
[email protected]c68a2b9b2013-10-09 18:16:361069 if (incremental_time_secs > 0) {
1070 int64 metrics_uptime = pref->GetInt64(prefs::kUninstallMetricsUptimeSec);
1071 metrics_uptime += incremental_time_secs;
1072 pref->SetInt64(prefs::kUninstallMetricsUptimeSec, metrics_uptime);
1073 }
initial.commit09911bf2008-07-26 23:55:291074}
1075
[email protected]2a321de32014-05-10 19:59:061076void MetricsService::AddObserver(MetricsServiceObserver* observer) {
1077 DCHECK(thread_checker_.CalledOnValidThread());
1078 observers_.AddObserver(observer);
1079}
1080
1081void MetricsService::RemoveObserver(MetricsServiceObserver* observer) {
1082 DCHECK(thread_checker_.CalledOnValidThread());
1083 observers_.RemoveObserver(observer);
1084}
1085
1086void MetricsService::NotifyOnDidCreateMetricsLog() {
1087 DCHECK(thread_checker_.CalledOnValidThread());
1088 FOR_EACH_OBSERVER(
1089 MetricsServiceObserver, observers_, OnDidCreateMetricsLog());
1090}
1091
initial.commit09911bf2008-07-26 23:55:291092//------------------------------------------------------------------------------
1093// State save methods
1094
1095void MetricsService::ScheduleNextStateSave() {
[email protected]8454aeb2011-11-19 23:38:201096 state_saver_factory_.InvalidateWeakPtrs();
initial.commit09911bf2008-07-26 23:55:291097
[email protected]b3a25092013-05-28 22:08:161098 base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
[email protected]8454aeb2011-11-19 23:38:201099 base::Bind(&MetricsService::SaveLocalState,
1100 state_saver_factory_.GetWeakPtr()),
[email protected]fc4252a72012-01-12 21:58:471101 base::TimeDelta::FromMinutes(kSaveStateIntervalMinutes));
initial.commit09911bf2008-07-26 23:55:291102}
1103
1104void MetricsService::SaveLocalState() {
1105 PrefService* pref = g_browser_process->local_state();
1106 if (!pref) {
[email protected]a063c102010-07-22 22:20:191107 NOTREACHED();
initial.commit09911bf2008-07-26 23:55:291108 return;
1109 }
1110
1111 RecordCurrentState(pref);
initial.commit09911bf2008-07-26 23:55:291112
[email protected]fc4252a72012-01-12 21:58:471113 // TODO(jar):110021 Does this run down the batteries????
initial.commit09911bf2008-07-26 23:55:291114 ScheduleNextStateSave();
1115}
1116
1117
1118//------------------------------------------------------------------------------
1119// Recording control methods
1120
[email protected]410938e02012-10-24 16:33:591121void MetricsService::OpenNewLog() {
1122 DCHECK(!log_manager_.current_log());
initial.commit09911bf2008-07-26 23:55:291123
[email protected]9eae4032014-04-09 19:15:191124 log_manager_.BeginLoggingWithLog(
[email protected]39076642014-05-05 20:32:551125 new MetricsLog(state_manager_->client_id(), session_id_,
1126 MetricsLog::ONGOING_LOG));
[email protected]2a321de32014-05-10 19:59:061127 NotifyOnDidCreateMetricsLog();
initial.commit09911bf2008-07-26 23:55:291128 if (state_ == INITIALIZED) {
1129 // We only need to schedule that run once.
[email protected]85ed9d42010-06-08 22:37:441130 state_ = INIT_TASK_SCHEDULED;
initial.commit09911bf2008-07-26 23:55:291131
[email protected]85ed9d42010-06-08 22:37:441132 // Schedules a task on the file thread for execution of slower
1133 // initialization steps (such as plugin list generation) necessary
1134 // for sending the initial log. This avoids blocking the main UI
1135 // thread.
[email protected]ed10dd12011-12-07 12:03:421136 BrowserThread::PostDelayedTask(
1137 BrowserThread::FILE,
1138 FROM_HERE,
[email protected]d33e7cc2011-09-23 01:43:561139 base::Bind(&MetricsService::InitTaskGetHardwareClass,
[email protected]c94d7382012-02-28 08:43:401140 self_ptr_factory_.GetWeakPtr(),
[email protected]b3a25092013-05-28 22:08:161141 base::MessageLoop::current()->message_loop_proxy()),
[email protected]7e560102012-03-08 20:58:421142 base::TimeDelta::FromSeconds(kInitializationDelaySeconds));
initial.commit09911bf2008-07-26 23:55:291143 }
1144}
1145
[email protected]410938e02012-10-24 16:33:591146void MetricsService::CloseCurrentLog() {
[email protected]cac267c2011-09-29 15:18:101147 if (!log_manager_.current_log())
initial.commit09911bf2008-07-26 23:55:291148 return;
1149
[email protected]68475e602008-08-22 03:21:151150 // TODO(jar): Integrate bounds on log recording more consistently, so that we
1151 // can stop recording logs that are too big much sooner.
[email protected]cac267c2011-09-29 15:18:101152 if (log_manager_.current_log()->num_events() > kEventLimit) {
[email protected]553dba62009-02-24 19:08:231153 UMA_HISTOGRAM_COUNTS("UMA.Discarded Log Events",
[email protected]cac267c2011-09-29 15:18:101154 log_manager_.current_log()->num_events());
1155 log_manager_.DiscardCurrentLog();
[email protected]410938e02012-10-24 16:33:591156 OpenNewLog(); // Start trivial log to hold our histograms.
[email protected]68475e602008-08-22 03:21:151157 }
1158
[email protected]cac267c2011-09-29 15:18:101159 // Adds to ongoing logs.
1160 log_manager_.current_log()->set_hardware_class(hardware_class_);
[email protected]accdfa62011-09-20 01:56:521161
[email protected]0b33f80b2008-12-17 21:34:361162 // Put incremental data (histogram deltas, and realtime stats deltas) at the
[email protected]147bbc0b2009-01-06 19:37:401163 // end of all log transmissions (initial log handles this separately).
[email protected]024b5cd2011-05-27 03:29:381164 // RecordIncrementalStabilityElements only exists on the derived
1165 // MetricsLog class.
[email protected]279703f2012-01-20 22:23:261166 MetricsLog* current_log =
1167 static_cast<MetricsLog*>(log_manager_.current_log());
[email protected]024b5cd2011-05-27 03:29:381168 DCHECK(current_log);
[email protected]b3610d42014-05-19 18:07:231169 std::vector<variations::ActiveGroupId> synthetic_trials;
[email protected]60677562013-11-17 15:52:551170 GetCurrentSyntheticFieldTrials(&synthetic_trials);
[email protected]0edf8762013-11-21 18:33:301171 current_log->RecordEnvironment(plugins_, google_update_metrics_,
1172 synthetic_trials);
[email protected]c68a2b9b2013-10-09 18:16:361173 PrefService* pref = g_browser_process->local_state();
[email protected]076961c2014-03-12 22:23:561174 base::TimeDelta incremental_uptime;
1175 base::TimeDelta uptime;
1176 GetUptimes(pref, &incremental_uptime, &uptime);
[email protected]9eae4032014-04-09 19:15:191177 current_log->RecordStabilityMetrics(incremental_uptime, uptime);
[email protected]60677562013-11-17 15:52:551178
[email protected]024b5cd2011-05-27 03:29:381179 RecordCurrentHistograms();
initial.commit09911bf2008-07-26 23:55:291180
[email protected]29948262012-03-01 12:15:081181 log_manager_.FinishCurrentLog();
initial.commit09911bf2008-07-26 23:55:291182}
1183
[email protected]cac267c2011-09-29 15:18:101184void MetricsService::PushPendingLogsToPersistentStorage() {
[email protected]80a8f312013-12-16 18:00:301185 if (state_ < SENDING_INITIAL_STABILITY_LOG)
[email protected]28ab7f92009-01-06 21:39:041186 return; // We didn't and still don't have time to get plugin list etc.
initial.commit09911bf2008-07-26 23:55:291187
[email protected]cac267c2011-09-29 15:18:101188 if (log_manager_.has_staged_log()) {
[email protected]7d41ae6d2012-06-26 08:53:031189 // We may race here, and send second copy of the log later.
[email protected]7f07db62014-05-15 01:12:451190 metrics::PersistedLogs::StoreType store_type;
[email protected]e3eb0c42013-04-18 06:18:581191 if (current_fetch_.get())
[email protected]7f07db62014-05-15 01:12:451192 store_type = metrics::PersistedLogs::PROVISIONAL_STORE;
[email protected]dc61fe92012-06-12 00:13:501193 else
[email protected]7f07db62014-05-15 01:12:451194 store_type = metrics::PersistedLogs::NORMAL_STORE;
[email protected]e7508d82012-05-03 15:59:531195 log_manager_.StoreStagedLogAsUnsent(store_type);
initial.commit09911bf2008-07-26 23:55:291196 }
[email protected]cac267c2011-09-29 15:18:101197 DCHECK(!log_manager_.has_staged_log());
[email protected]410938e02012-10-24 16:33:591198 CloseCurrentLog();
[email protected]80a8f312013-12-16 18:00:301199 log_manager_.PersistUnsentLogs();
[email protected]7d41ae6d2012-06-26 08:53:031200
1201 // If there was a staged and/or current log, then there is now at least one
1202 // log waiting to be uploaded.
1203 if (log_manager_.has_unsent_logs())
1204 state_ = SENDING_OLD_LOGS;
initial.commit09911bf2008-07-26 23:55:291205}
1206
1207//------------------------------------------------------------------------------
1208// Transmission of logs methods
1209
[email protected]7f7f1962011-04-20 15:58:161210void MetricsService::StartSchedulerIfNecessary() {
[email protected]410938e02012-10-24 16:33:591211 // Never schedule cutting or uploading of logs in test mode.
1212 if (test_mode_active_)
1213 return;
1214
1215 // Even if reporting is disabled, the scheduler is needed to trigger the
1216 // creation of the initial log, which must be done in order for any logs to be
1217 // persisted on shutdown or backgrounding.
[email protected]80a8f312013-12-16 18:00:301218 if (recording_active() &&
1219 (reporting_active() || state_ < SENDING_INITIAL_STABILITY_LOG)) {
[email protected]7f7f1962011-04-20 15:58:161220 scheduler_->Start();
[email protected]80a8f312013-12-16 18:00:301221 }
initial.commit09911bf2008-07-26 23:55:291222}
1223
[email protected]7f7f1962011-04-20 15:58:161224void MetricsService::StartScheduledUpload() {
[email protected]cd1ac712012-06-26 08:26:471225 // If we're getting no notifications, then the log won't have much in it, and
1226 // it's possible the computer is about to go to sleep, so don't upload and
1227 // stop the scheduler.
[email protected]410938e02012-10-24 16:33:591228 // If recording has been turned off, the scheduler doesn't need to run.
1229 // If reporting is off, proceed if the initial log hasn't been created, since
1230 // that has to happen in order for logs to be cut and stored when persisting.
[email protected]cd1ac712012-06-26 08:26:471231 // TODO(stuartmorgan): Call Stop() on the schedule when reporting and/or
1232 // recording are turned off instead of letting it fire and then aborting.
1233 if (idle_since_last_transmission_ ||
[email protected]410938e02012-10-24 16:33:591234 !recording_active() ||
[email protected]80a8f312013-12-16 18:00:301235 (!reporting_active() && state_ >= SENDING_INITIAL_STABILITY_LOG)) {
[email protected]7f7f1962011-04-20 15:58:161236 scheduler_->Stop();
1237 scheduler_->UploadCancelled();
1238 return;
1239 }
1240
[email protected]c15faf372012-07-11 06:01:341241 // If the callback was to upload an old log, but there no longer is one,
1242 // just report success back to the scheduler to begin the ongoing log
1243 // callbacks.
1244 // TODO(stuartmorgan): Consider removing the distinction between
1245 // SENDING_OLD_LOGS and SENDING_CURRENT_LOGS to simplify the state machine
1246 // now that the log upload flow is the same for both modes.
1247 if (state_ == SENDING_OLD_LOGS && !log_manager_.has_unsent_logs()) {
1248 state_ = SENDING_CURRENT_LOGS;
1249 scheduler_->UploadFinished(true /* healthy */, false /* no unsent logs */);
1250 return;
1251 }
[email protected]cd1ac712012-06-26 08:26:471252 // If there are unsent logs, send the next one. If not, start the asynchronous
1253 // process of finalizing the current log for upload.
1254 if (state_ == SENDING_OLD_LOGS) {
1255 DCHECK(log_manager_.has_unsent_logs());
1256 log_manager_.StageNextLogForUpload();
1257 SendStagedLog();
1258 } else {
1259 StartFinalLogInfoCollection();
1260 }
[email protected]29948262012-03-01 12:15:081261}
1262
1263void MetricsService::StartFinalLogInfoCollection() {
1264 // Begin the multi-step process of collecting memory usage histograms:
1265 // First spawn a task to collect the memory details; when that task is
1266 // finished, it will call OnMemoryDetailCollectionDone. That will in turn
1267 // call HistogramSynchronization to collect histograms from all renderers and
1268 // then call OnHistogramSynchronizationDone to continue processing.
[email protected]d119f222012-06-08 02:33:271269 DCHECK(!waiting_for_asynchronous_reporting_step_);
1270 waiting_for_asynchronous_reporting_step_ = true;
[email protected]7f7f1962011-04-20 15:58:161271
[email protected]2226c222011-11-22 00:08:401272 base::Closure callback =
1273 base::Bind(&MetricsService::OnMemoryDetailCollectionDone,
[email protected]c94d7382012-02-28 08:43:401274 self_ptr_factory_.GetWeakPtr());
[email protected]84c988a2011-04-19 17:56:331275
[email protected]2226c222011-11-22 00:08:401276 scoped_refptr<MetricsMemoryDetails> details(
1277 new MetricsMemoryDetails(callback));
[email protected]4306df72012-04-20 18:58:571278 details->StartFetch(MemoryDetails::UPDATE_USER_METRICS);
[email protected]84c988a2011-04-19 17:56:331279
1280 // Collect WebCore cache information to put into a histogram.
[email protected]f3b1a082011-11-18 00:34:301281 for (content::RenderProcessHost::iterator i(
1282 content::RenderProcessHost::AllHostsIterator());
[email protected]84c988a2011-04-19 17:56:331283 !i.IsAtEnd(); i.Advance())
[email protected]2ccf45c2011-08-19 23:35:501284 i.GetCurrentValue()->Send(new ChromeViewMsg_GetCacheResourceStats());
[email protected]84c988a2011-04-19 17:56:331285}
1286
1287void MetricsService::OnMemoryDetailCollectionDone() {
[email protected]c9a3ef82009-05-28 22:02:461288 DCHECK(IsSingleThreaded());
[email protected]7f7f1962011-04-20 15:58:161289 // This function should only be called as the callback from an ansynchronous
1290 // step.
[email protected]d119f222012-06-08 02:33:271291 DCHECK(waiting_for_asynchronous_reporting_step_);
[email protected]c9a3ef82009-05-28 22:02:461292
[email protected]c9a3ef82009-05-28 22:02:461293 // Create a callback_task for OnHistogramSynchronizationDone.
[email protected]2226c222011-11-22 00:08:401294 base::Closure callback = base::Bind(
1295 &MetricsService::OnHistogramSynchronizationDone,
[email protected]c94d7382012-02-28 08:43:401296 self_ptr_factory_.GetWeakPtr());
[email protected]c9a3ef82009-05-28 22:02:461297
[email protected]a3079832013-10-24 20:29:361298 base::TimeDelta timeout =
1299 base::TimeDelta::FromMilliseconds(kMaxHistogramGatheringWaitDuration);
1300
1301 DCHECK_EQ(num_async_histogram_fetches_in_progress_, 0);
1302
1303#if defined(OS_ANDROID)
1304 // Android has no service process.
1305 num_async_histogram_fetches_in_progress_ = 1;
1306#else // OS_ANDROID
1307 num_async_histogram_fetches_in_progress_ = 2;
1308 // Run requests to service and content in parallel.
1309 if (!ServiceProcessControl::GetInstance()->GetHistograms(callback, timeout)) {
1310 // Assume |num_async_histogram_fetches_in_progress_| is not changed by
1311 // |GetHistograms()|.
1312 DCHECK_EQ(num_async_histogram_fetches_in_progress_, 2);
1313 // Assign |num_async_histogram_fetches_in_progress_| above and decrement it
1314 // here to make code work even if |GetHistograms()| fired |callback|.
1315 --num_async_histogram_fetches_in_progress_;
1316 }
1317#endif // OS_ANDROID
1318
[email protected]c9a3ef82009-05-28 22:02:461319 // Set up the callback to task to call after we receive histograms from all
[email protected]83ab4a282012-07-12 18:19:451320 // child processes. Wait time specifies how long to wait before absolutely
[email protected]c9a3ef82009-05-28 22:02:461321 // calling us back on the task.
[email protected]a3079832013-10-24 20:29:361322 content::FetchHistogramsAsynchronously(base::MessageLoop::current(), callback,
1323 timeout);
[email protected]c9a3ef82009-05-28 22:02:461324}
1325
1326void MetricsService::OnHistogramSynchronizationDone() {
initial.commit09911bf2008-07-26 23:55:291327 DCHECK(IsSingleThreaded());
[email protected]29948262012-03-01 12:15:081328 // This function should only be called as the callback from an ansynchronous
1329 // step.
[email protected]d119f222012-06-08 02:33:271330 DCHECK(waiting_for_asynchronous_reporting_step_);
[email protected]a3079832013-10-24 20:29:361331 DCHECK_GT(num_async_histogram_fetches_in_progress_, 0);
1332
1333 // Check if all expected requests finished.
1334 if (--num_async_histogram_fetches_in_progress_ > 0)
1335 return;
initial.commit09911bf2008-07-26 23:55:291336
[email protected]d119f222012-06-08 02:33:271337 waiting_for_asynchronous_reporting_step_ = false;
[email protected]29948262012-03-01 12:15:081338 OnFinalLogInfoCollectionDone();
1339}
1340
1341void MetricsService::OnFinalLogInfoCollectionDone() {
[email protected]7f7f1962011-04-20 15:58:161342 // If somehow there is a fetch in progress, we return and hope things work
1343 // out. The scheduler isn't informed since if this happens, the scheduler
1344 // will get a response from the upload.
[email protected]e3eb0c42013-04-18 06:18:581345 DCHECK(!current_fetch_.get());
1346 if (current_fetch_.get())
[email protected]7f7f1962011-04-20 15:58:161347 return;
1348
[email protected]cd1ac712012-06-26 08:26:471349 // Abort if metrics were turned off during the final info gathering.
[email protected]410938e02012-10-24 16:33:591350 if (!recording_active()) {
[email protected]7f7f1962011-04-20 15:58:161351 scheduler_->Stop();
1352 scheduler_->UploadCancelled();
[email protected]d01b8732008-10-16 02:18:071353 return;
1354 }
1355
[email protected]cd1ac712012-06-26 08:26:471356 StageNewLog();
[email protected]410938e02012-10-24 16:33:591357
1358 // If logs shouldn't be uploaded, stop here. It's important that this check
1359 // be after StageNewLog(), otherwise the previous logs will never be loaded,
1360 // and thus the open log won't be persisted.
1361 // TODO(stuartmorgan): This is unnecessarily complicated; restructure loading
1362 // of previous logs to not require running part of the upload logic.
1363 // http://crbug.com/157337
1364 if (!reporting_active()) {
1365 scheduler_->Stop();
1366 scheduler_->UploadCancelled();
1367 return;
1368 }
1369
[email protected]29948262012-03-01 12:15:081370 SendStagedLog();
1371}
1372
[email protected]cd1ac712012-06-26 08:26:471373void MetricsService::StageNewLog() {
[email protected]29948262012-03-01 12:15:081374 if (log_manager_.has_staged_log())
1375 return;
1376
1377 switch (state_) {
1378 case INITIALIZED:
1379 case INIT_TASK_SCHEDULED: // We should be further along by now.
[email protected]dc61fe92012-06-12 00:13:501380 NOTREACHED();
[email protected]29948262012-03-01 12:15:081381 return;
1382
1383 case INIT_TASK_DONE:
[email protected]80a8f312013-12-16 18:00:301384 if (has_initial_stability_log_) {
1385 // There's an initial stability log, ready to send.
1386 log_manager_.StageNextLogForUpload();
1387 has_initial_stability_log_ = false;
[email protected]f61eb842014-01-22 10:59:131388 // Note: No need to call LoadPersistedUnsentLogs() here because unsent
1389 // logs have already been loaded by PrepareInitialStabilityLog().
[email protected]80a8f312013-12-16 18:00:301390 state_ = SENDING_INITIAL_STABILITY_LOG;
1391 } else {
[email protected]b58b8b22014-04-08 22:40:331392 PrepareInitialMetricsLog();
[email protected]f61eb842014-01-22 10:59:131393 // Load unsent logs (if any) from local state.
1394 log_manager_.LoadPersistedUnsentLogs();
[email protected]80a8f312013-12-16 18:00:301395 state_ = SENDING_INITIAL_METRICS_LOG;
1396 }
[email protected]29948262012-03-01 12:15:081397 break;
1398
1399 case SENDING_OLD_LOGS:
[email protected]cd1ac712012-06-26 08:26:471400 NOTREACHED(); // Shouldn't be staging a new log during old log sending.
1401 return;
[email protected]29948262012-03-01 12:15:081402
1403 case SENDING_CURRENT_LOGS:
[email protected]410938e02012-10-24 16:33:591404 CloseCurrentLog();
1405 OpenNewLog();
[email protected]29948262012-03-01 12:15:081406 log_manager_.StageNextLogForUpload();
1407 break;
1408
1409 default:
1410 NOTREACHED();
1411 return;
1412 }
1413
1414 DCHECK(log_manager_.has_staged_log());
1415}
1416
[email protected]80a8f312013-12-16 18:00:301417void MetricsService::PrepareInitialStabilityLog() {
1418 DCHECK_EQ(INITIALIZED, state_);
1419 PrefService* pref = g_browser_process->local_state();
1420 DCHECK_NE(0, pref->GetInteger(prefs::kStabilityCrashCount));
[email protected]29948262012-03-01 12:15:081421
[email protected]80a8f312013-12-16 18:00:301422 scoped_ptr<MetricsLog> initial_stability_log(
[email protected]39076642014-05-05 20:32:551423 new MetricsLog(state_manager_->client_id(), session_id_,
[email protected]9eae4032014-04-09 19:15:191424 MetricsLog::INITIAL_STABILITY_LOG));
[email protected]2a321de32014-05-10 19:59:061425
1426 // Do not call NotifyOnDidCreateMetricsLog here because the stability
1427 // log describes stats from the _previous_ session.
1428
[email protected]80a8f312013-12-16 18:00:301429 if (!initial_stability_log->LoadSavedEnvironmentFromPrefs())
1430 return;
[email protected]9eae4032014-04-09 19:15:191431 initial_stability_log->RecordStabilityMetrics(base::TimeDelta(),
1432 base::TimeDelta());
[email protected]80a8f312013-12-16 18:00:301433 log_manager_.LoadPersistedUnsentLogs();
1434
1435 log_manager_.PauseCurrentLog();
[email protected]9eae4032014-04-09 19:15:191436 log_manager_.BeginLoggingWithLog(initial_stability_log.release());
[email protected]c778687a2014-02-11 14:46:451437#if defined(OS_ANDROID)
1438 ConvertAndroidStabilityPrefsToHistograms(pref);
1439 RecordCurrentStabilityHistograms();
1440#endif // defined(OS_ANDROID)
[email protected]80a8f312013-12-16 18:00:301441 log_manager_.FinishCurrentLog();
1442 log_manager_.ResumePausedLog();
1443
1444 // Store unsent logs, including the stability log that was just saved, so
1445 // that they're not lost in case of a crash before upload time.
1446 log_manager_.PersistUnsentLogs();
1447
1448 has_initial_stability_log_ = true;
1449}
1450
[email protected]b58b8b22014-04-08 22:40:331451void MetricsService::PrepareInitialMetricsLog() {
[email protected]80a8f312013-12-16 18:00:301452 DCHECK(state_ == INIT_TASK_DONE || state_ == SENDING_INITIAL_STABILITY_LOG);
1453 initial_metrics_log_->set_hardware_class(hardware_class_);
[email protected]0edf8762013-11-21 18:33:301454
[email protected]b3610d42014-05-19 18:07:231455 std::vector<variations::ActiveGroupId> synthetic_trials;
[email protected]60677562013-11-17 15:52:551456 GetCurrentSyntheticFieldTrials(&synthetic_trials);
[email protected]80a8f312013-12-16 18:00:301457 initial_metrics_log_->RecordEnvironment(plugins_, google_update_metrics_,
1458 synthetic_trials);
[email protected]0edf8762013-11-21 18:33:301459 PrefService* pref = g_browser_process->local_state();
[email protected]076961c2014-03-12 22:23:561460 base::TimeDelta incremental_uptime;
1461 base::TimeDelta uptime;
1462 GetUptimes(pref, &incremental_uptime, &uptime);
[email protected]9eae4032014-04-09 19:15:191463 initial_metrics_log_->RecordStabilityMetrics(incremental_uptime, uptime);
[email protected]29948262012-03-01 12:15:081464
1465 // Histograms only get written to the current log, so make the new log current
1466 // before writing them.
1467 log_manager_.PauseCurrentLog();
[email protected]9eae4032014-04-09 19:15:191468 log_manager_.BeginLoggingWithLog(initial_metrics_log_.release());
[email protected]c778687a2014-02-11 14:46:451469#if defined(OS_ANDROID)
1470 ConvertAndroidStabilityPrefsToHistograms(pref);
1471#endif // defined(OS_ANDROID)
[email protected]29948262012-03-01 12:15:081472 RecordCurrentHistograms();
1473 log_manager_.FinishCurrentLog();
1474 log_manager_.ResumePausedLog();
1475
1476 DCHECK(!log_manager_.has_staged_log());
1477 log_manager_.StageNextLogForUpload();
1478}
1479
[email protected]29948262012-03-01 12:15:081480void MetricsService::SendStagedLog() {
1481 DCHECK(log_manager_.has_staged_log());
1482
[email protected]cac267c2011-09-29 15:18:101483 PrepareFetchWithStagedLog();
[email protected]d01b8732008-10-16 02:18:071484
[email protected]e3eb0c42013-04-18 06:18:581485 bool upload_created = (current_fetch_.get() != NULL);
[email protected]d6bebb92012-06-13 23:14:551486 UMA_HISTOGRAM_BOOLEAN("UMA.UploadCreation", upload_created);
1487 if (!upload_created) {
[email protected]d01b8732008-10-16 02:18:071488 // Compression failed, and log discarded :-/.
[email protected]dc61fe92012-06-12 00:13:501489 // Skip this upload and hope things work out next time.
[email protected]cac267c2011-09-29 15:18:101490 log_manager_.DiscardStagedLog();
[email protected]7f7f1962011-04-20 15:58:161491 scheduler_->UploadCancelled();
[email protected]d01b8732008-10-16 02:18:071492 return;
1493 }
1494
[email protected]d119f222012-06-08 02:33:271495 DCHECK(!waiting_for_asynchronous_reporting_step_);
[email protected]d119f222012-06-08 02:33:271496 waiting_for_asynchronous_reporting_step_ = true;
[email protected]dc61fe92012-06-12 00:13:501497
[email protected]e3eb0c42013-04-18 06:18:581498 current_fetch_->Start();
[email protected]d01b8732008-10-16 02:18:071499
1500 HandleIdleSinceLastTransmission(true);
1501}
1502
[email protected]cac267c2011-09-29 15:18:101503void MetricsService::PrepareFetchWithStagedLog() {
[email protected]dc61fe92012-06-12 00:13:501504 DCHECK(log_manager_.has_staged_log());
[email protected]cac78842008-11-27 01:02:201505
[email protected]fe58acc22012-02-29 01:29:581506 // Prepare the protobuf version.
[email protected]e3eb0c42013-04-18 06:18:581507 DCHECK(!current_fetch_.get());
[email protected]5f3e1642013-05-05 03:37:341508 if (log_manager_.has_staged_log()) {
[email protected]e3eb0c42013-04-18 06:18:581509 current_fetch_.reset(net::URLFetcher::Create(
[email protected]5f3e1642013-05-05 03:37:341510 GURL(kServerUrl), net::URLFetcher::POST, this));
[email protected]e3eb0c42013-04-18 06:18:581511 current_fetch_->SetRequestContext(
[email protected]fe58acc22012-02-29 01:29:581512 g_browser_process->system_request_context());
[email protected]537c638d2013-07-04 00:49:191513
[email protected]7f07db62014-05-15 01:12:451514 std::string log_text = log_manager_.staged_log();
[email protected]8df71322013-09-13 18:40:001515 std::string compressed_log_text;
1516 bool compression_successful = chrome::GzipCompress(log_text,
1517 &compressed_log_text);
1518 DCHECK(compression_successful);
1519 if (compression_successful) {
1520 current_fetch_->SetUploadData(kMimeType, compressed_log_text);
1521 // Tell the server that we're uploading gzipped protobufs.
1522 current_fetch_->SetExtraRequestHeaders("content-encoding: gzip");
[email protected]cfee9aa52013-10-19 17:53:051523 const std::string hash =
1524 base::HexEncode(log_manager_.staged_log_hash().data(),
1525 log_manager_.staged_log_hash().size());
1526 DCHECK(!hash.empty());
1527 current_fetch_->AddExtraRequestHeader("X-Chrome-UMA-Log-SHA1: " + hash);
[email protected]8df71322013-09-13 18:40:001528 UMA_HISTOGRAM_PERCENTAGE(
1529 "UMA.ProtoCompressionRatio",
1530 100 * compressed_log_text.size() / log_text.size());
1531 UMA_HISTOGRAM_CUSTOM_COUNTS(
1532 "UMA.ProtoGzippedKBSaved",
1533 (log_text.size() - compressed_log_text.size()) / 1024,
1534 1, 2000, 50);
[email protected]537c638d2013-07-04 00:49:191535 }
[email protected]537c638d2013-07-04 00:49:191536
[email protected]fe58acc22012-02-29 01:29:581537 // We already drop cookies server-side, but we might as well strip them out
1538 // client-side as well.
[email protected]e3eb0c42013-04-18 06:18:581539 current_fetch_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES |
1540 net::LOAD_DO_NOT_SEND_COOKIES);
[email protected]fe58acc22012-02-29 01:29:581541 }
initial.commit09911bf2008-07-26 23:55:291542}
1543
[email protected]10c2d692012-05-11 05:32:231544void MetricsService::OnURLFetchComplete(const net::URLFetcher* source) {
[email protected]d119f222012-06-08 02:33:271545 DCHECK(waiting_for_asynchronous_reporting_step_);
[email protected]fe58acc22012-02-29 01:29:581546
1547 // We're not allowed to re-use the existing |URLFetcher|s, so free them here.
[email protected]e3eb0c42013-04-18 06:18:581548 // Note however that |source| is aliased to the fetcher, so we should be
[email protected]4266def22012-05-17 01:02:401549 // careful not to delete it too early.
[email protected]e3eb0c42013-04-18 06:18:581550 DCHECK_EQ(current_fetch_.get(), source);
1551 scoped_ptr<net::URLFetcher> s(current_fetch_.Pass());
[email protected]fe58acc22012-02-29 01:29:581552
[email protected]dc61fe92012-06-12 00:13:501553 int response_code = source->GetResponseCode();
[email protected]fe58acc22012-02-29 01:29:581554
[email protected]dc61fe92012-06-12 00:13:501555 // Log a histogram to track response success vs. failure rates.
[email protected]e3eb0c42013-04-18 06:18:581556 UMA_HISTOGRAM_ENUMERATION("UMA.UploadResponseStatus.Protobuf",
1557 ResponseCodeToStatus(response_code),
1558 NUM_RESPONSE_STATUSES);
[email protected]fe58acc22012-02-29 01:29:581559
[email protected]e7508d82012-05-03 15:59:531560 // If the upload was provisionally stored, drop it now that the upload is
1561 // known to have gone through.
1562 log_manager_.DiscardLastProvisionalStore();
initial.commit09911bf2008-07-26 23:55:291563
[email protected]dc61fe92012-06-12 00:13:501564 bool upload_succeeded = response_code == 200;
[email protected]7f7f1962011-04-20 15:58:161565
[email protected]0eb34fee2009-01-21 08:04:381566 // Provide boolean for error recovery (allow us to ignore response_code).
[email protected]dc6f4962009-02-13 01:25:501567 bool discard_log = false;
[email protected]7f07db62014-05-15 01:12:451568 const size_t log_size = log_manager_.staged_log().length();
[email protected]dc61fe92012-06-12 00:13:501569 if (!upload_succeeded && log_size > kUploadLogAvoidRetransmitSize) {
1570 UMA_HISTOGRAM_COUNTS("UMA.Large Rejected Log was Discarded",
1571 static_cast<int>(log_size));
[email protected]0eb34fee2009-01-21 08:04:381572 discard_log = true;
[email protected]dc61fe92012-06-12 00:13:501573 } else if (response_code == 400) {
[email protected]0eb34fee2009-01-21 08:04:381574 // Bad syntax. Retransmission won't work.
[email protected]0eb34fee2009-01-21 08:04:381575 discard_log = true;
[email protected]68475e602008-08-22 03:21:151576 }
1577
[email protected]e3eb0c42013-04-18 06:18:581578 if (upload_succeeded || discard_log)
[email protected]5f3e1642013-05-05 03:37:341579 log_manager_.DiscardStagedLog();
[email protected]dc61fe92012-06-12 00:13:501580
1581 waiting_for_asynchronous_reporting_step_ = false;
1582
1583 if (!log_manager_.has_staged_log()) {
initial.commit09911bf2008-07-26 23:55:291584 switch (state_) {
[email protected]80a8f312013-12-16 18:00:301585 case SENDING_INITIAL_STABILITY_LOG:
1586 // Store the updated list to disk now that the removed log is uploaded.
1587 log_manager_.PersistUnsentLogs();
[email protected]b58b8b22014-04-08 22:40:331588 PrepareInitialMetricsLog();
[email protected]80a8f312013-12-16 18:00:301589 SendStagedLog();
1590 state_ = SENDING_INITIAL_METRICS_LOG;
1591 break;
1592
1593 case SENDING_INITIAL_METRICS_LOG:
1594 // The initial metrics log never gets persisted to local state, so it's
1595 // not necessary to call log_manager_.PersistUnsentLogs() here.
1596 // TODO(asvitkine): It should be persisted like the initial stability
1597 // log and old unsent logs. http://crbug.com/328417
[email protected]cd1ac712012-06-26 08:26:471598 state_ = log_manager_.has_unsent_logs() ? SENDING_OLD_LOGS
1599 : SENDING_CURRENT_LOGS;
initial.commit09911bf2008-07-26 23:55:291600 break;
1601
initial.commit09911bf2008-07-26 23:55:291602 case SENDING_OLD_LOGS:
[email protected]d53e2232011-06-30 15:54:571603 // Store the updated list to disk now that the removed log is uploaded.
[email protected]80a8f312013-12-16 18:00:301604 log_manager_.PersistUnsentLogs();
[email protected]cd1ac712012-06-26 08:26:471605 if (!log_manager_.has_unsent_logs())
1606 state_ = SENDING_CURRENT_LOGS;
initial.commit09911bf2008-07-26 23:55:291607 break;
1608
1609 case SENDING_CURRENT_LOGS:
1610 break;
1611
1612 default:
[email protected]a063c102010-07-22 22:20:191613 NOTREACHED();
initial.commit09911bf2008-07-26 23:55:291614 break;
1615 }
[email protected]d01b8732008-10-16 02:18:071616
[email protected]cac267c2011-09-29 15:18:101617 if (log_manager_.has_unsent_logs())
[email protected]ed0fd002012-04-25 23:10:341618 DCHECK_LT(state_, SENDING_CURRENT_LOGS);
initial.commit09911bf2008-07-26 23:55:291619 }
[email protected]252873ef2008-08-04 21:59:451620
[email protected]7f7f1962011-04-20 15:58:161621 // Error 400 indicates a problem with the log, not with the server, so
1622 // don't consider that a sign that the server is in trouble.
[email protected]dc61fe92012-06-12 00:13:501623 bool server_is_healthy = upload_succeeded || response_code == 400;
[email protected]80a8f312013-12-16 18:00:301624 // Don't notify the scheduler that the upload is finished if we've only sent
1625 // the initial stability log, but not yet the initial metrics log (treat the
1626 // two as a single unit of work as far as the scheduler is concerned).
1627 if (state_ != SENDING_INITIAL_METRICS_LOG) {
1628 scheduler_->UploadFinished(server_is_healthy,
1629 log_manager_.has_unsent_logs());
1630 }
[email protected]d67d1052011-06-09 05:11:411631
1632 // Collect network stats if UMA upload succeeded.
[email protected]b8ddb052012-04-19 02:36:061633 IOThread* io_thread = g_browser_process->io_thread();
1634 if (server_is_healthy && io_thread) {
1635 chrome_browser_net::CollectNetworkStats(network_stats_server_, io_thread);
[email protected]adbb3762012-03-09 22:20:081636 chrome_browser_net::CollectPipeliningCapabilityStatsOnUIThread(
[email protected]b8ddb052012-04-19 02:36:061637 http_pipelining_test_server_, io_thread);
[email protected]aa312812013-04-30 19:46:051638#if defined(OS_WIN)
1639 chrome::CollectTimeTicksStats();
1640#endif
[email protected]adbb3762012-03-09 22:20:081641 }
initial.commit09911bf2008-07-26 23:55:291642}
1643
[email protected]57ecc4b2010-08-11 03:02:511644void MetricsService::IncrementPrefValue(const char* path) {
[email protected]e73c01972008-08-13 00:18:241645 PrefService* pref = g_browser_process->local_state();
1646 DCHECK(pref);
1647 int value = pref->GetInteger(path);
1648 pref->SetInteger(path, value + 1);
1649}
1650
[email protected]57ecc4b2010-08-11 03:02:511651void MetricsService::IncrementLongPrefsValue(const char* path) {
[email protected]0bb1a622009-03-04 03:22:321652 PrefService* pref = g_browser_process->local_state();
1653 DCHECK(pref);
1654 int64 value = pref->GetInt64(path);
[email protected]b42c5e42010-06-03 20:43:251655 pref->SetInt64(path, value + 1);
[email protected]0bb1a622009-03-04 03:22:321656}
1657
[email protected]752a5262013-06-23 14:53:421658void MetricsService::LogLoadStarted(content::WebContents* web_contents) {
[email protected]e6e30ac2014-01-13 21:24:391659 content::RecordAction(base::UserMetricsAction("PageLoad"));
[email protected]dd8d12a2011-09-02 02:10:151660 HISTOGRAM_ENUMERATION("Chrome.UmaPageloadCounter", 1, 2);
[email protected]e73c01972008-08-13 00:18:241661 IncrementPrefValue(prefs::kStabilityPageLoadCount);
[email protected]0bb1a622009-03-04 03:22:321662 IncrementLongPrefsValue(prefs::kUninstallMetricsPageLoadCount);
[email protected]0b33f80b2008-12-17 21:34:361663 // We need to save the prefs, as page load count is a critical stat, and it
1664 // might be lost due to a crash :-(.
initial.commit09911bf2008-07-26 23:55:291665}
1666
[email protected]c3721482012-03-23 16:21:481667void MetricsService::LogRendererCrash(content::RenderProcessHost* host,
1668 base::TerminationStatus status,
[email protected]f1675202012-07-09 15:18:001669 int exit_code) {
[email protected]6f371442011-11-09 06:45:461670 bool was_extension_process =
[email protected]fafdc842014-01-17 18:09:081671 extensions::ProcessMap::Get(host->GetBrowserContext())
1672 ->Contains(host->GetID());
[email protected]c3721482012-03-23 16:21:481673 if (status == base::TERMINATION_STATUS_PROCESS_CRASHED ||
1674 status == base::TERMINATION_STATUS_ABNORMAL_TERMINATION) {
[email protected]d7c1fa62012-06-15 23:35:301675 if (was_extension_process) {
[email protected]718eab62011-10-05 21:16:521676 IncrementPrefValue(prefs::kStabilityExtensionRendererCrashCount);
[email protected]d7c1fa62012-06-15 23:35:301677
[email protected]1026afd2013-03-20 14:28:541678 UMA_HISTOGRAM_SPARSE_SLOWLY("CrashExitCodes.Extension",
1679 MapCrashExitCodeForHistogram(exit_code));
[email protected]d7c1fa62012-06-15 23:35:301680 } else {
[email protected]718eab62011-10-05 21:16:521681 IncrementPrefValue(prefs::kStabilityRendererCrashCount);
initial.commit09911bf2008-07-26 23:55:291682
[email protected]1026afd2013-03-20 14:28:541683 UMA_HISTOGRAM_SPARSE_SLOWLY("CrashExitCodes.Renderer",
1684 MapCrashExitCodeForHistogram(exit_code));
[email protected]d7c1fa62012-06-15 23:35:301685 }
1686
[email protected]718eab62011-10-05 21:16:521687 UMA_HISTOGRAM_PERCENTAGE("BrowserRenderProcessHost.ChildCrashes",
1688 was_extension_process ? 2 : 1);
[email protected]c3721482012-03-23 16:21:481689 } else if (status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED) {
[email protected]718eab62011-10-05 21:16:521690 UMA_HISTOGRAM_PERCENTAGE("BrowserRenderProcessHost.ChildKills",
1691 was_extension_process ? 2 : 1);
[email protected]f1675202012-07-09 15:18:001692 } else if (status == base::TERMINATION_STATUS_STILL_RUNNING) {
1693 UMA_HISTOGRAM_PERCENTAGE("BrowserRenderProcessHost.DisconnectedAlive",
[email protected]718eab62011-10-05 21:16:521694 was_extension_process ? 2 : 1);
[email protected]718eab62011-10-05 21:16:521695 }
[email protected]80a8f312013-12-16 18:00:301696}
[email protected]1f085622009-12-04 05:33:451697
initial.commit09911bf2008-07-26 23:55:291698void MetricsService::LogRendererHang() {
[email protected]e73c01972008-08-13 00:18:241699 IncrementPrefValue(prefs::kStabilityRendererHangCount);
initial.commit09911bf2008-07-26 23:55:291700}
1701
[email protected]c0c55e92011-09-10 18:47:301702bool MetricsService::UmaMetricsProperlyShutdown() {
1703 CHECK(clean_shutdown_status_ == CLEANLY_SHUTDOWN ||
1704 clean_shutdown_status_ == NEED_TO_SHUTDOWN);
1705 return clean_shutdown_status_ == CLEANLY_SHUTDOWN;
1706}
1707
[email protected]60677562013-11-17 15:52:551708void MetricsService::RegisterSyntheticFieldTrial(
1709 const SyntheticTrialGroup& trial) {
1710 for (size_t i = 0; i < synthetic_trial_groups_.size(); ++i) {
1711 if (synthetic_trial_groups_[i].id.name == trial.id.name) {
1712 if (synthetic_trial_groups_[i].id.group != trial.id.group) {
1713 synthetic_trial_groups_[i].id.group = trial.id.group;
[email protected]7a5c07812014-02-26 11:45:411714 synthetic_trial_groups_[i].start_time = base::TimeTicks::Now();
[email protected]60677562013-11-17 15:52:551715 }
1716 return;
1717 }
1718 }
1719
[email protected]7a5c07812014-02-26 11:45:411720 SyntheticTrialGroup trial_group = trial;
1721 trial_group.start_time = base::TimeTicks::Now();
[email protected]60677562013-11-17 15:52:551722 synthetic_trial_groups_.push_back(trial_group);
1723}
1724
[email protected]99c892d2014-03-24 18:11:211725void MetricsService::CheckForClonedInstall() {
[email protected]39076642014-05-05 20:32:551726 state_manager_->CheckForClonedInstall();
[email protected]99c892d2014-03-24 18:11:211727}
1728
[email protected]60677562013-11-17 15:52:551729void MetricsService::GetCurrentSyntheticFieldTrials(
[email protected]b3610d42014-05-19 18:07:231730 std::vector<variations::ActiveGroupId>* synthetic_trials) {
[email protected]60677562013-11-17 15:52:551731 DCHECK(synthetic_trials);
1732 synthetic_trials->clear();
1733 const MetricsLog* current_log =
1734 static_cast<const MetricsLog*>(log_manager_.current_log());
1735 for (size_t i = 0; i < synthetic_trial_groups_.size(); ++i) {
1736 if (synthetic_trial_groups_[i].start_time <= current_log->creation_time())
1737 synthetic_trials->push_back(synthetic_trial_groups_[i].id);
1738 }
1739}
1740
[email protected]466f3c12011-03-23 21:20:381741void MetricsService::LogCleanShutdown() {
[email protected]acd55b32011-09-05 17:35:311742 // Redundant hack to write pref ASAP.
[email protected]84c384e2013-03-01 23:20:191743 MarkAppCleanShutdownAndCommit();
1744
[email protected]c0c55e92011-09-10 18:47:301745 // Redundant setting to assure that we always reset this value at shutdown
1746 // (and that we don't use some alternate path, and not call LogCleanShutdown).
1747 clean_shutdown_status_ = CLEANLY_SHUTDOWN;
[email protected]acd55b32011-09-05 17:35:311748
[email protected]466f3c12011-03-23 21:20:381749 RecordBooleanPrefValue(prefs::kStabilityExitedCleanly, true);
[email protected]6a6d0d12013-10-28 15:58:191750 PrefService* pref = g_browser_process->local_state();
1751 pref->SetInteger(prefs::kStabilityExecutionPhase,
[email protected]6d67ea0d2013-11-14 11:02:211752 MetricsService::SHUTDOWN_COMPLETE);
[email protected]466f3c12011-03-23 21:20:381753}
1754
[email protected]c1834a92011-01-21 18:21:031755#if defined(OS_CHROMEOS)
1756void MetricsService::LogChromeOSCrash(const std::string &crash_type) {
1757 if (crash_type == "user")
1758 IncrementPrefValue(prefs::kStabilityOtherUserCrashCount);
1759 else if (crash_type == "kernel")
1760 IncrementPrefValue(prefs::kStabilityKernelCrashCount);
1761 else if (crash_type == "uncleanshutdown")
1762 IncrementPrefValue(prefs::kStabilitySystemUncleanShutdownCount);
1763 else
1764 NOTREACHED() << "Unexpected Chrome OS crash type " << crash_type;
1765 // Wake up metrics logs sending if necessary now that new
1766 // log data is available.
1767 HandleIdleSinceLastTransmission(false);
1768}
1769#endif // OS_CHROMEOS
1770
[email protected]650b2d52013-02-10 03:41:451771void MetricsService::LogPluginLoadingError(const base::FilePath& plugin_path) {
[email protected]d7bd3e52013-07-21 04:29:201772 content::WebPluginInfo plugin;
[email protected]cd937072012-07-02 09:00:291773 bool success =
1774 content::PluginService::GetInstance()->GetPluginInfoByPath(plugin_path,
1775 &plugin);
1776 DCHECK(success);
1777 ChildProcessStats& stats = child_process_stats_buffer_[plugin.name];
1778 // Initialize the type if this entry is new.
1779 if (stats.process_type == content::PROCESS_TYPE_UNKNOWN) {
1780 // The plug-in process might not actually of type PLUGIN (which means
1781 // NPAPI), but we only care that it is *a* plug-in process.
1782 stats.process_type = content::PROCESS_TYPE_PLUGIN;
1783 } else {
1784 DCHECK(IsPluginProcess(stats.process_type));
1785 }
1786 stats.loading_errors++;
1787}
1788
[email protected]f4eaf7b92013-02-28 22:00:401789MetricsService::ChildProcessStats& MetricsService::GetChildProcessStats(
1790 const content::ChildProcessData& data) {
[email protected]439f1e32013-12-09 20:09:091791 const base::string16& child_name = data.name;
[email protected]f3b357692013-03-22 05:16:131792 if (!ContainsKey(child_process_stats_buffer_, child_name)) {
1793 child_process_stats_buffer_[child_name] =
1794 ChildProcessStats(data.process_type);
1795 }
[email protected]f4eaf7b92013-02-28 22:00:401796 return child_process_stats_buffer_[child_name];
initial.commit09911bf2008-07-26 23:55:291797}
1798
initial.commit09911bf2008-07-26 23:55:291799void MetricsService::RecordPluginChanges(PrefService* pref) {
[email protected]f8628c22011-04-05 12:10:181800 ListPrefUpdate update(pref, prefs::kStabilityPluginStats);
[email protected]cb1078de2013-12-23 20:04:221801 base::ListValue* plugins = update.Get();
initial.commit09911bf2008-07-26 23:55:291802 DCHECK(plugins);
1803
[email protected]cb1078de2013-12-23 20:04:221804 for (base::ListValue::iterator value_iter = plugins->begin();
initial.commit09911bf2008-07-26 23:55:291805 value_iter != plugins->end(); ++value_iter) {
[email protected]cb1078de2013-12-23 20:04:221806 if (!(*value_iter)->IsType(base::Value::TYPE_DICTIONARY)) {
[email protected]a063c102010-07-22 22:20:191807 NOTREACHED();
initial.commit09911bf2008-07-26 23:55:291808 continue;
1809 }
1810
[email protected]cb1078de2013-12-23 20:04:221811 base::DictionaryValue* plugin_dict =
1812 static_cast<base::DictionaryValue*>(*value_iter);
[email protected]57ecc4b2010-08-11 03:02:511813 std::string plugin_name;
[email protected]8e50b602009-03-03 22:59:431814 plugin_dict->GetString(prefs::kStabilityPluginName, &plugin_name);
[email protected]6470ee8f2009-03-03 20:46:401815 if (plugin_name.empty()) {
[email protected]a063c102010-07-22 22:20:191816 NOTREACHED();
initial.commit09911bf2008-07-26 23:55:291817 continue;
1818 }
1819
[email protected]57ecc4b2010-08-11 03:02:511820 // TODO(viettrungluu): remove conversions
[email protected]6778fed2013-12-24 20:09:371821 base::string16 name16 = base::UTF8ToUTF16(plugin_name);
[email protected]68b9e72b2011-08-05 23:08:221822 if (child_process_stats_buffer_.find(name16) ==
1823 child_process_stats_buffer_.end()) {
initial.commit09911bf2008-07-26 23:55:291824 continue;
[email protected]68b9e72b2011-08-05 23:08:221825 }
initial.commit09911bf2008-07-26 23:55:291826
[email protected]68b9e72b2011-08-05 23:08:221827 ChildProcessStats stats = child_process_stats_buffer_[name16];
initial.commit09911bf2008-07-26 23:55:291828 if (stats.process_launches) {
1829 int launches = 0;
[email protected]8e50b602009-03-03 22:59:431830 plugin_dict->GetInteger(prefs::kStabilityPluginLaunches, &launches);
initial.commit09911bf2008-07-26 23:55:291831 launches += stats.process_launches;
[email protected]8e50b602009-03-03 22:59:431832 plugin_dict->SetInteger(prefs::kStabilityPluginLaunches, launches);
initial.commit09911bf2008-07-26 23:55:291833 }
1834 if (stats.process_crashes) {
1835 int crashes = 0;
[email protected]8e50b602009-03-03 22:59:431836 plugin_dict->GetInteger(prefs::kStabilityPluginCrashes, &crashes);
initial.commit09911bf2008-07-26 23:55:291837 crashes += stats.process_crashes;
[email protected]8e50b602009-03-03 22:59:431838 plugin_dict->SetInteger(prefs::kStabilityPluginCrashes, crashes);
initial.commit09911bf2008-07-26 23:55:291839 }
1840 if (stats.instances) {
1841 int instances = 0;
[email protected]8e50b602009-03-03 22:59:431842 plugin_dict->GetInteger(prefs::kStabilityPluginInstances, &instances);
initial.commit09911bf2008-07-26 23:55:291843 instances += stats.instances;
[email protected]8e50b602009-03-03 22:59:431844 plugin_dict->SetInteger(prefs::kStabilityPluginInstances, instances);
initial.commit09911bf2008-07-26 23:55:291845 }
[email protected]cd937072012-07-02 09:00:291846 if (stats.loading_errors) {
1847 int loading_errors = 0;
1848 plugin_dict->GetInteger(prefs::kStabilityPluginLoadingErrors,
1849 &loading_errors);
1850 loading_errors += stats.loading_errors;
1851 plugin_dict->SetInteger(prefs::kStabilityPluginLoadingErrors,
1852 loading_errors);
1853 }
initial.commit09911bf2008-07-26 23:55:291854
[email protected]68b9e72b2011-08-05 23:08:221855 child_process_stats_buffer_.erase(name16);
initial.commit09911bf2008-07-26 23:55:291856 }
1857
1858 // Now go through and add dictionaries for plugins that didn't already have
1859 // reports in Local State.
[email protected]d2065e062013-12-12 23:49:521860 for (std::map<base::string16, ChildProcessStats>::iterator cache_iter =
[email protected]a27a9382009-02-11 23:55:101861 child_process_stats_buffer_.begin();
1862 cache_iter != child_process_stats_buffer_.end(); ++cache_iter) {
[email protected]a27a9382009-02-11 23:55:101863 ChildProcessStats stats = cache_iter->second;
[email protected]0d84c5d2009-10-09 01:10:421864
1865 // Insert only plugins information into the plugins list.
[email protected]8d5f1dae2011-11-11 14:30:411866 if (!IsPluginProcess(stats.process_type))
[email protected]0d84c5d2009-10-09 01:10:421867 continue;
1868
[email protected]57ecc4b2010-08-11 03:02:511869 // TODO(viettrungluu): remove conversion
[email protected]6778fed2013-12-24 20:09:371870 std::string plugin_name = base::UTF16ToUTF8(cache_iter->first);
[email protected]0d84c5d2009-10-09 01:10:421871
[email protected]cb1078de2013-12-23 20:04:221872 base::DictionaryValue* plugin_dict = new base::DictionaryValue;
initial.commit09911bf2008-07-26 23:55:291873
[email protected]8e50b602009-03-03 22:59:431874 plugin_dict->SetString(prefs::kStabilityPluginName, plugin_name);
1875 plugin_dict->SetInteger(prefs::kStabilityPluginLaunches,
initial.commit09911bf2008-07-26 23:55:291876 stats.process_launches);
[email protected]8e50b602009-03-03 22:59:431877 plugin_dict->SetInteger(prefs::kStabilityPluginCrashes,
initial.commit09911bf2008-07-26 23:55:291878 stats.process_crashes);
[email protected]8e50b602009-03-03 22:59:431879 plugin_dict->SetInteger(prefs::kStabilityPluginInstances,
initial.commit09911bf2008-07-26 23:55:291880 stats.instances);
[email protected]cd937072012-07-02 09:00:291881 plugin_dict->SetInteger(prefs::kStabilityPluginLoadingErrors,
1882 stats.loading_errors);
initial.commit09911bf2008-07-26 23:55:291883 plugins->Append(plugin_dict);
1884 }
[email protected]a27a9382009-02-11 23:55:101885 child_process_stats_buffer_.clear();
initial.commit09911bf2008-07-26 23:55:291886}
1887
[email protected]e5ad60a2014-03-11 03:54:041888bool MetricsService::ShouldLogEvents() {
1889 // We simply don't log events to UMA if there is a single incognito
initial.commit09911bf2008-07-26 23:55:291890 // session visible. The problem is that we always notify using the orginal
1891 // profile in order to simplify notification processing.
[email protected]e764e582012-08-01 03:01:291892 return !chrome::IsOffTheRecordSessionActive();
initial.commit09911bf2008-07-26 23:55:291893}
1894
[email protected]57ecc4b2010-08-11 03:02:511895void MetricsService::RecordBooleanPrefValue(const char* path, bool value) {
initial.commit09911bf2008-07-26 23:55:291896 DCHECK(IsSingleThreaded());
1897
1898 PrefService* pref = g_browser_process->local_state();
1899 DCHECK(pref);
1900
1901 pref->SetBoolean(path, value);
1902 RecordCurrentState(pref);
1903}
1904
1905void MetricsService::RecordCurrentState(PrefService* pref) {
[email protected]0bb1a622009-03-04 03:22:321906 pref->SetInt64(prefs::kStabilityLastTimestampSec, Time::Now().ToTimeT());
initial.commit09911bf2008-07-26 23:55:291907
1908 RecordPluginChanges(pref);
1909}
1910
[email protected]8d5f1dae2011-11-11 14:30:411911// static
[email protected]f3b357692013-03-22 05:16:131912bool MetricsService::IsPluginProcess(int process_type) {
1913 return (process_type == content::PROCESS_TYPE_PLUGIN ||
1914 process_type == content::PROCESS_TYPE_PPAPI_PLUGIN ||
1915 process_type == content::PROCESS_TYPE_PPAPI_BROKER);
[email protected]8d5f1dae2011-11-11 14:30:411916}
1917
[email protected]5ccaa412009-11-13 22:00:161918#if defined(OS_CHROMEOS)
[email protected]29cf16772010-04-21 15:13:471919void MetricsService::StartExternalMetrics() {
[email protected]5ccaa412009-11-13 22:00:161920 external_metrics_ = new chromeos::ExternalMetrics;
[email protected]29cf16772010-04-21 15:13:471921 external_metrics_->Start();
[email protected]5ccaa412009-11-13 22:00:161922}
1923#endif
[email protected]3819f2ee2011-08-21 09:44:381924
1925// static
1926bool MetricsServiceHelper::IsMetricsReportingEnabled() {
1927 bool result = false;
1928 const PrefService* local_state = g_browser_process->local_state();
1929 if (local_state) {
1930 const PrefService::Preference* uma_pref =
1931 local_state->FindPreference(prefs::kMetricsReportingEnabled);
1932 if (uma_pref) {
1933 bool success = uma_pref->GetValue()->GetAsBoolean(&result);
1934 DCHECK(success);
1935 }
1936 }
1937 return result;
1938}
[email protected]1ef13cf2014-03-21 22:44:011939
1940bool MetricsServiceHelper::IsCrashReportingEnabled() {
1941#if defined(GOOGLE_CHROME_BUILD)
1942#if defined(OS_CHROMEOS)
1943 bool reporting_enabled = false;
1944 chromeos::CrosSettings::Get()->GetBoolean(chromeos::kStatsReportingPref,
1945 &reporting_enabled);
1946 return reporting_enabled;
1947#elif defined(OS_ANDROID)
1948 // Android has its own settings for metrics / crash uploading.
1949 const PrefService* prefs = g_browser_process->local_state();
1950 return prefs->GetBoolean(prefs::kCrashReportingEnabled);
1951#else
1952 return MetricsServiceHelper::IsMetricsReportingEnabled();
1953#endif
1954#else
1955 return false;
1956#endif
1957}
[email protected]2a321de32014-05-10 19:59:061958
1959void MetricsServiceHelper::AddMetricsServiceObserver(
1960 MetricsServiceObserver* observer) {
1961 MetricsService* metrics_service = g_browser_process->metrics_service();
1962 if (metrics_service)
1963 metrics_service->AddObserver(observer);
1964}
1965
1966void MetricsServiceHelper::RemoveMetricsServiceObserver(
1967 MetricsServiceObserver* observer) {
1968 MetricsService* metrics_service = g_browser_process->metrics_service();
1969 if (metrics_service)
1970 metrics_service->RemoveObserver(observer);
1971}