blob: 1cb20ecce3735e884eab8ba0b5ff4503bf721ba3 [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]cac267c2011-09-29 15:18:10190#include "chrome/browser/metrics/metrics_log_serializer.h"
[email protected]7f7f1962011-04-20 15:58:16191#include "chrome/browser/metrics/metrics_reporting_scheduler.h"
[email protected]39076642014-05-05 20:32:55192#include "chrome/browser/metrics/metrics_state_manager.h"
[email protected]aa312812013-04-30 19:46:05193#include "chrome/browser/metrics/time_ticks_experiment_win.h"
[email protected]ed0fd002012-04-25 23:10:34194#include "chrome/browser/metrics/tracking_synchronizer.h"
[email protected]60677562013-11-17 15:52:55195#include "chrome/common/metrics/variations/variations_util.h"
[email protected]adbb3762012-03-09 22:20:08196#include "chrome/browser/net/http_pipelining_compatibility_client.h"
[email protected]d67d1052011-06-09 05:11:41197#include "chrome/browser/net/network_stats.h"
[email protected]0fafc8d2013-06-01 00:09:50198#include "chrome/browser/omnibox/omnibox_log.h"
[email protected]10b132b02012-07-27 20:46:18199#include "chrome/browser/ui/browser_otr_state.h"
[email protected]261ab7c2013-08-19 15:04:58200#include "chrome/common/chrome_constants.h"
[email protected]92745242009-06-12 16:52:21201#include "chrome/common/chrome_switches.h"
[email protected]264c0acac2013-10-01 13:33:30202#include "chrome/common/crash_keys.h"
[email protected]b4a72d842012-03-22 20:09:09203#include "chrome/common/net/test_server_locations.h"
initial.commit09911bf2008-07-26 23:55:29204#include "chrome/common/pref_names.h"
[email protected]e09ba552009-02-05 03:26:29205#include "chrome/common/render_messages.h"
[email protected]064107e2014-05-02 00:59:06206#include "components/metrics/metrics_log_manager.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]5f3e1642013-05-05 03:37:34447 registry->RegisterListPref(prefs::kMetricsInitialLogs);
448 registry->RegisterListPref(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)
463 : state_manager_(state_manager),
[email protected]37d4709a2014-03-29 03:07:40464 recording_active_(false),
[email protected]d01b8732008-10-16 02:18:07465 reporting_active_(false),
[email protected]410938e02012-10-24 16:33:59466 test_mode_active_(false),
[email protected]d01b8732008-10-16 02:18:07467 state_(INITIALIZED),
[email protected]80a8f312013-12-16 18:00:30468 has_initial_stability_log_(false),
[email protected]d01b8732008-10-16 02:18:07469 idle_since_last_transmission_(false),
[email protected]80a8f312013-12-16 18:00:30470 session_id_(-1),
initial.commit09911bf2008-07-26 23:55:29471 next_window_id_(0),
[email protected]9c009092013-05-01 03:14:09472 self_ptr_factory_(this),
473 state_saver_factory_(this),
[email protected]e5354322012-08-09 23:07:37474 waiting_for_asynchronous_reporting_step_(false),
[email protected]39076642014-05-05 20:32:55475 num_async_histogram_fetches_in_progress_(0) {
initial.commit09911bf2008-07-26 23:55:29476 DCHECK(IsSingleThreaded());
[email protected]39076642014-05-05 20:32:55477 DCHECK(state_manager_);
[email protected]7f7f1962011-04-20 15:58:16478
[email protected]80a8f312013-12-16 18:00:30479 log_manager_.set_log_serializer(new MetricsLogSerializer);
[email protected]cac267c2011-09-29 15:18:10480 log_manager_.set_max_ongoing_log_store_size(kUploadLogAvoidRetransmitSize);
[email protected]f4eaf7b92013-02-28 22:00:40481
482 BrowserChildProcessObserver::Add(this);
initial.commit09911bf2008-07-26 23:55:29483}
484
485MetricsService::~MetricsService() {
[email protected]410938e02012-10-24 16:33:59486 DisableRecording();
[email protected]f4eaf7b92013-02-28 22:00:40487
488 BrowserChildProcessObserver::Remove(this);
initial.commit09911bf2008-07-26 23:55:29489}
490
[email protected]39076642014-05-05 20:32:55491void MetricsService::InitializeMetricsRecordingState() {
492 InitializeMetricsState();
[email protected]80a8f312013-12-16 18:00:30493
494 base::Closure callback = base::Bind(&MetricsService::StartScheduledUpload,
495 self_ptr_factory_.GetWeakPtr());
496 scheduler_.reset(new MetricsReportingScheduler(callback));
497}
498
[email protected]d01b8732008-10-16 02:18:07499void MetricsService::Start() {
[email protected]b1c8dc02011-04-13 18:32:04500 HandleIdleSinceLastTransmission(false);
[email protected]410938e02012-10-24 16:33:59501 EnableRecording();
502 EnableReporting();
[email protected]d01b8732008-10-16 02:18:07503}
504
[email protected]39076642014-05-05 20:32:55505bool MetricsService::StartIfMetricsReportingEnabled() {
506 const bool enabled = state_manager_->IsMetricsReportingEnabled();
507 if (enabled)
508 Start();
509 return enabled;
510}
511
[email protected]410938e02012-10-24 16:33:59512void MetricsService::StartRecordingForTests() {
513 test_mode_active_ = true;
514 EnableRecording();
515 DisableReporting();
[email protected]d01b8732008-10-16 02:18:07516}
517
518void MetricsService::Stop() {
[email protected]b1c8dc02011-04-13 18:32:04519 HandleIdleSinceLastTransmission(false);
[email protected]410938e02012-10-24 16:33:59520 DisableReporting();
521 DisableRecording();
522}
523
524void MetricsService::EnableReporting() {
525 if (reporting_active_)
526 return;
527 reporting_active_ = true;
528 StartSchedulerIfNecessary();
529}
530
531void MetricsService::DisableReporting() {
532 reporting_active_ = false;
[email protected]d01b8732008-10-16 02:18:07533}
534
[email protected]edafd4c2011-05-10 17:18:53535std::string MetricsService::GetClientId() {
[email protected]39076642014-05-05 20:32:55536 return state_manager_->client_id();
[email protected]edafd4c2011-05-10 17:18:53537}
538
[email protected]20f999b52012-08-24 22:32:59539scoped_ptr<const base::FieldTrial::EntropyProvider>
[email protected]39076642014-05-05 20:32:55540MetricsService::CreateEntropyProvider() {
541 // TODO(asvitkine): Refactor the code so that MetricsService does not expose
542 // this method.
543 return state_manager_->CreateEntropyProvider();
[email protected]5cbeeef72012-02-08 02:05:18544}
545
[email protected]410938e02012-10-24 16:33:59546void MetricsService::EnableRecording() {
initial.commit09911bf2008-07-26 23:55:29547 DCHECK(IsSingleThreaded());
548
[email protected]410938e02012-10-24 16:33:59549 if (recording_active_)
initial.commit09911bf2008-07-26 23:55:29550 return;
[email protected]410938e02012-10-24 16:33:59551 recording_active_ = true;
initial.commit09911bf2008-07-26 23:55:29552
[email protected]39076642014-05-05 20:32:55553 state_manager_->ForceClientIdCreation();
554 crash_keys::SetClientID(state_manager_->client_id());
[email protected]410938e02012-10-24 16:33:59555 if (!log_manager_.current_log())
556 OpenNewLog();
[email protected]005ef3e2009-05-22 20:55:46557
[email protected]410938e02012-10-24 16:33:59558 SetUpNotifications(&registrar_, this);
[email protected]e6e30ac2014-01-13 21:24:39559 base::RemoveActionCallback(action_callback_);
[email protected]dd98f392013-02-04 13:03:22560 action_callback_ = base::Bind(&MetricsService::OnUserAction,
561 base::Unretained(this));
[email protected]e6e30ac2014-01-13 21:24:39562 base::AddActionCallback(action_callback_);
[email protected]410938e02012-10-24 16:33:59563}
564
565void MetricsService::DisableRecording() {
566 DCHECK(IsSingleThreaded());
567
568 if (!recording_active_)
569 return;
570 recording_active_ = false;
571
[email protected]e6e30ac2014-01-13 21:24:39572 base::RemoveActionCallback(action_callback_);
[email protected]410938e02012-10-24 16:33:59573 registrar_.RemoveAll();
574 PushPendingLogsToPersistentStorage();
575 DCHECK(!log_manager_.has_staged_log());
initial.commit09911bf2008-07-26 23:55:29576}
577
[email protected]d01b8732008-10-16 02:18:07578bool MetricsService::recording_active() const {
initial.commit09911bf2008-07-26 23:55:29579 DCHECK(IsSingleThreaded());
[email protected]d01b8732008-10-16 02:18:07580 return recording_active_;
initial.commit09911bf2008-07-26 23:55:29581}
582
[email protected]d01b8732008-10-16 02:18:07583bool MetricsService::reporting_active() const {
584 DCHECK(IsSingleThreaded());
585 return reporting_active_;
initial.commit09911bf2008-07-26 23:55:29586}
587
[email protected]87ef9ea2011-02-26 03:15:15588// static
[email protected]6c2381d2011-10-19 02:52:53589void MetricsService::SetUpNotifications(
590 content::NotificationRegistrar* registrar,
591 content::NotificationObserver* observer) {
592 registrar->Add(observer, chrome::NOTIFICATION_BROWSER_OPENED,
[email protected]ad50def52011-10-19 23:17:07593 content::NotificationService::AllBrowserContextsAndSources());
[email protected]6c2381d2011-10-19 02:52:53594 registrar->Add(observer, chrome::NOTIFICATION_BROWSER_CLOSED,
[email protected]ad50def52011-10-19 23:17:07595 content::NotificationService::AllSources());
[email protected]884033e2012-04-16 19:38:42596 registrar->Add(observer, chrome::NOTIFICATION_TAB_PARENTED,
[email protected]ad50def52011-10-19 23:17:07597 content::NotificationService::AllSources());
[email protected]884033e2012-04-16 19:38:42598 registrar->Add(observer, chrome::NOTIFICATION_TAB_CLOSING,
[email protected]ad50def52011-10-19 23:17:07599 content::NotificationService::AllSources());
[email protected]6c2381d2011-10-19 02:52:53600 registrar->Add(observer, content::NOTIFICATION_LOAD_START,
[email protected]ad50def52011-10-19 23:17:07601 content::NotificationService::AllSources());
[email protected]6c2381d2011-10-19 02:52:53602 registrar->Add(observer, content::NOTIFICATION_LOAD_STOP,
[email protected]ad50def52011-10-19 23:17:07603 content::NotificationService::AllSources());
[email protected]6c2381d2011-10-19 02:52:53604 registrar->Add(observer, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
[email protected]ad50def52011-10-19 23:17:07605 content::NotificationService::AllSources());
[email protected]42d8d7582013-11-09 01:24:38606 registrar->Add(observer, content::NOTIFICATION_RENDER_WIDGET_HOST_HANG,
[email protected]ad50def52011-10-19 23:17:07607 content::NotificationService::AllSources());
[email protected]6c2381d2011-10-19 02:52:53608 registrar->Add(observer, chrome::NOTIFICATION_OMNIBOX_OPENED_URL,
[email protected]ad50def52011-10-19 23:17:07609 content::NotificationService::AllSources());
[email protected]87ef9ea2011-02-26 03:15:15610}
611
[email protected]f4eaf7b92013-02-28 22:00:40612void MetricsService::BrowserChildProcessHostConnected(
613 const content::ChildProcessData& data) {
614 GetChildProcessStats(data).process_launches++;
615}
616
617void MetricsService::BrowserChildProcessCrashed(
618 const content::ChildProcessData& data) {
619 GetChildProcessStats(data).process_crashes++;
620 // Exclude plugin crashes from the count below because we report them via
621 // a separate UMA metric.
[email protected]f3b357692013-03-22 05:16:13622 if (!IsPluginProcess(data.process_type))
[email protected]f4eaf7b92013-02-28 22:00:40623 IncrementPrefValue(prefs::kStabilityChildProcessCrashCount);
624}
625
626void MetricsService::BrowserChildProcessInstanceCreated(
627 const content::ChildProcessData& data) {
628 GetChildProcessStats(data).instances++;
629}
630
[email protected]432115822011-07-10 15:52:27631void MetricsService::Observe(int type,
[email protected]6c2381d2011-10-19 02:52:53632 const content::NotificationSource& source,
633 const content::NotificationDetails& details) {
[email protected]cac267c2011-09-29 15:18:10634 DCHECK(log_manager_.current_log());
initial.commit09911bf2008-07-26 23:55:29635 DCHECK(IsSingleThreaded());
636
[email protected]e5ad60a2014-03-11 03:54:04637 // Check for notifications related to core stability metrics, or that are
638 // just triggers to end idle mode. Anything else should be added in the later
639 // switch statement, where they take effect only if general metrics should be
640 // logged.
641 bool handled = false;
[email protected]432115822011-07-10 15:52:27642 switch (type) {
[email protected]432115822011-07-10 15:52:27643 case chrome::NOTIFICATION_BROWSER_OPENED:
[email protected]46a0efc2013-07-17 15:40:47644 case chrome::NOTIFICATION_BROWSER_CLOSED:
645 case chrome::NOTIFICATION_TAB_PARENTED:
646 case chrome::NOTIFICATION_TAB_CLOSING:
[email protected]432115822011-07-10 15:52:27647 case content::NOTIFICATION_LOAD_STOP:
[email protected]e5ad60a2014-03-11 03:54:04648 // These notifications are used only to break out of idle mode.
649 handled = true;
initial.commit09911bf2008-07-26 23:55:29650 break;
651
[email protected]752a5262013-06-23 14:53:42652 case content::NOTIFICATION_LOAD_START: {
653 content::NavigationController* controller =
654 content::Source<content::NavigationController>(source).ptr();
655 content::WebContents* web_contents = controller->GetWebContents();
656 LogLoadStarted(web_contents);
[email protected]e5ad60a2014-03-11 03:54:04657 handled = true;
initial.commit09911bf2008-07-26 23:55:29658 break;
[email protected]752a5262013-06-23 14:53:42659 }
initial.commit09911bf2008-07-26 23:55:29660
[email protected]432115822011-07-10 15:52:27661 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: {
[email protected]e5ad60a2014-03-11 03:54:04662 content::RenderProcessHost::RendererClosedDetails* process_details =
663 content::Details<
664 content::RenderProcessHost::RendererClosedDetails>(
665 details).ptr();
666 content::RenderProcessHost* host =
667 content::Source<content::RenderProcessHost>(source).ptr();
668 LogRendererCrash(
669 host, process_details->status, process_details->exit_code);
670 handled = true;
initial.commit09911bf2008-07-26 23:55:29671 break;
[email protected]1226abb2010-06-10 18:01:28672 }
initial.commit09911bf2008-07-26 23:55:29673
[email protected]e5ad60a2014-03-11 03:54:04674 case content::NOTIFICATION_RENDER_WIDGET_HOST_HANG:
675 LogRendererHang();
676 handled = true;
initial.commit09911bf2008-07-26 23:55:29677 break;
[email protected]e5ad60a2014-03-11 03:54:04678
679 default:
680 // Everything else is handled after the early return check below.
681 break;
682 }
683
684 // If it wasn't one of the stability-related notifications, and event
685 // logging isn't suppressed, handle it.
686 if (!handled && ShouldLogEvents()) {
687 switch (type) {
688 case chrome::NOTIFICATION_OMNIBOX_OPENED_URL: {
689 MetricsLog* current_log =
690 static_cast<MetricsLog*>(log_manager_.current_log());
691 DCHECK(current_log);
692 current_log->RecordOmniboxOpenedURL(
693 *content::Details<OmniboxLog>(details).ptr());
694 break;
695 }
696
697 default:
698 NOTREACHED();
699 break;
700 }
initial.commit09911bf2008-07-26 23:55:29701 }
[email protected]d01b8732008-10-16 02:18:07702
703 HandleIdleSinceLastTransmission(false);
[email protected]d01b8732008-10-16 02:18:07704}
705
706void MetricsService::HandleIdleSinceLastTransmission(bool in_idle) {
707 // If there wasn't a lot of action, maybe the computer was asleep, in which
708 // case, the log transmissions should have stopped. Here we start them up
709 // again.
[email protected]cac78842008-11-27 01:02:20710 if (!in_idle && idle_since_last_transmission_)
[email protected]7f7f1962011-04-20 15:58:16711 StartSchedulerIfNecessary();
[email protected]cac78842008-11-27 01:02:20712 idle_since_last_transmission_ = in_idle;
initial.commit09911bf2008-07-26 23:55:29713}
714
initial.commit09911bf2008-07-26 23:55:29715void MetricsService::RecordStartOfSessionEnd() {
[email protected]466f3c12011-03-23 21:20:38716 LogCleanShutdown();
initial.commit09911bf2008-07-26 23:55:29717 RecordBooleanPrefValue(prefs::kStabilitySessionEndCompleted, false);
718}
719
720void MetricsService::RecordCompletedSessionEnd() {
[email protected]466f3c12011-03-23 21:20:38721 LogCleanShutdown();
initial.commit09911bf2008-07-26 23:55:29722 RecordBooleanPrefValue(prefs::kStabilitySessionEndCompleted, true);
723}
724
[email protected]410938e02012-10-24 16:33:59725#if defined(OS_ANDROID) || defined(OS_IOS)
[email protected]117fbdf22012-06-26 18:36:39726void MetricsService::OnAppEnterBackground() {
727 scheduler_->Stop();
728
[email protected]84c384e2013-03-01 23:20:19729 MarkAppCleanShutdownAndCommit();
[email protected]117fbdf22012-06-26 18:36:39730
731 // At this point, there's no way of knowing when the process will be
732 // killed, so this has to be treated similar to a shutdown, closing and
733 // persisting all logs. Unlinke a shutdown, the state is primed to be ready
734 // to continue logging and uploading if the process does return.
[email protected]80a8f312013-12-16 18:00:30735 if (recording_active() && state_ >= SENDING_INITIAL_STABILITY_LOG) {
[email protected]117fbdf22012-06-26 18:36:39736 PushPendingLogsToPersistentStorage();
[email protected]410938e02012-10-24 16:33:59737 // Persisting logs closes the current log, so start recording a new log
738 // immediately to capture any background work that might be done before the
739 // process is killed.
740 OpenNewLog();
[email protected]117fbdf22012-06-26 18:36:39741 }
[email protected]117fbdf22012-06-26 18:36:39742}
743
744void MetricsService::OnAppEnterForeground() {
745 PrefService* pref = g_browser_process->local_state();
746 pref->SetBoolean(prefs::kStabilityExitedCleanly, false);
747
748 StartSchedulerIfNecessary();
749}
[email protected]84c384e2013-03-01 23:20:19750#else
751void MetricsService::LogNeedForCleanShutdown() {
752 PrefService* pref = g_browser_process->local_state();
753 pref->SetBoolean(prefs::kStabilityExitedCleanly, false);
754 // Redundant setting to be sure we call for a clean shutdown.
755 clean_shutdown_status_ = NEED_TO_SHUTDOWN;
756}
757#endif // defined(OS_ANDROID) || defined(OS_IOS)
[email protected]117fbdf22012-06-26 18:36:39758
[email protected]6d67ea0d2013-11-14 11:02:21759// static
760void MetricsService::SetExecutionPhase(ExecutionPhase execution_phase) {
761 execution_phase_ = execution_phase;
762 PrefService* pref = g_browser_process->local_state();
763 pref->SetInteger(prefs::kStabilityExecutionPhase, execution_phase_);
764}
765
[email protected]7f7f1962011-04-20 15:58:16766void MetricsService::RecordBreakpadRegistration(bool success) {
[email protected]68475e602008-08-22 03:21:15767 if (!success)
[email protected]e73c01972008-08-13 00:18:24768 IncrementPrefValue(prefs::kStabilityBreakpadRegistrationFail);
769 else
770 IncrementPrefValue(prefs::kStabilityBreakpadRegistrationSuccess);
771}
772
773void MetricsService::RecordBreakpadHasDebugger(bool has_debugger) {
774 if (!has_debugger)
775 IncrementPrefValue(prefs::kStabilityDebuggerNotPresent);
776 else
[email protected]68475e602008-08-22 03:21:15777 IncrementPrefValue(prefs::kStabilityDebuggerPresent);
[email protected]e73c01972008-08-13 00:18:24778}
779
[email protected]261ab7c2013-08-19 15:04:58780#if defined(OS_WIN)
781void MetricsService::CountBrowserCrashDumpAttempts() {
[email protected]a5e0fe5e2013-09-16 06:15:45782 // Open the registry key for iteration.
[email protected]261ab7c2013-08-19 15:04:58783 base::win::RegKey regkey;
784 if (regkey.Open(HKEY_CURRENT_USER,
[email protected]a5e0fe5e2013-09-16 06:15:45785 chrome::kBrowserCrashDumpAttemptsRegistryPath,
[email protected]261ab7c2013-08-19 15:04:58786 KEY_ALL_ACCESS) != ERROR_SUCCESS) {
787 return;
788 }
789
[email protected]a5e0fe5e2013-09-16 06:15:45790 // The values we're interested in counting are all prefixed with the version.
791 base::string16 chrome_version(base::ASCIIToUTF16(chrome::kChromeVersion));
792
793 // Track a list of values to delete. We don't modify the registry key while
794 // we're iterating over its values.
795 typedef std::vector<base::string16> StringVector;
796 StringVector to_delete;
797
798 // Iterate over the values in the key counting dumps with and without crashes.
799 // We directly walk the values instead of using RegistryValueIterator in order
800 // to read all of the values as DWORDS instead of strings.
801 base::string16 name;
802 DWORD value = 0;
803 int dumps_with_crash = 0;
804 int dumps_with_no_crash = 0;
[email protected]261ab7c2013-08-19 15:04:58805 for (int i = regkey.GetValueCount() - 1; i >= 0; --i) {
[email protected]a5e0fe5e2013-09-16 06:15:45806 if (regkey.GetValueNameAt(i, &name) == ERROR_SUCCESS &&
807 StartsWith(name, chrome_version, false) &&
808 regkey.ReadValueDW(name.c_str(), &value) == ERROR_SUCCESS) {
809 to_delete.push_back(name);
810 if (value == 0)
811 ++dumps_with_no_crash;
812 else
813 ++dumps_with_crash;
[email protected]261ab7c2013-08-19 15:04:58814 }
815 }
[email protected]a5e0fe5e2013-09-16 06:15:45816
817 // Delete the registry keys we've just counted.
818 for (StringVector::iterator i = to_delete.begin(); i != to_delete.end(); ++i)
819 regkey.DeleteValue(i->c_str());
820
821 // Capture the histogram samples.
822 if (dumps_with_crash != 0)
823 UMA_HISTOGRAM_COUNTS("Chrome.BrowserDumpsWithCrash", dumps_with_crash);
824 if (dumps_with_no_crash != 0)
825 UMA_HISTOGRAM_COUNTS("Chrome.BrowserDumpsWithNoCrash", dumps_with_no_crash);
826 int total_dumps = dumps_with_crash + dumps_with_no_crash;
827 if (total_dumps != 0)
828 UMA_HISTOGRAM_COUNTS("Chrome.BrowserCrashDumpAttempts", total_dumps);
[email protected]261ab7c2013-08-19 15:04:58829}
830#endif // defined(OS_WIN)
831
initial.commit09911bf2008-07-26 23:55:29832//------------------------------------------------------------------------------
833// private methods
834//------------------------------------------------------------------------------
835
836
837//------------------------------------------------------------------------------
838// Initialization methods
839
[email protected]39076642014-05-05 20:32:55840void MetricsService::InitializeMetricsState() {
[email protected]79bf0b72009-04-27 21:30:55841#if defined(OS_POSIX)
[email protected]b4a72d842012-03-22 20:09:09842 network_stats_server_ = chrome_common_net::kEchoTestServerLocation;
843 http_pipelining_test_server_ = chrome_common_net::kPipelineTestServerBaseUrl;
[email protected]79bf0b72009-04-27 21:30:55844#else
845 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
[email protected]d67d1052011-06-09 05:11:41846 network_stats_server_ = dist->GetNetworkStatsServer();
[email protected]adbb3762012-03-09 22:20:08847 http_pipelining_test_server_ = dist->GetHttpPipeliningTestServer();
[email protected]79bf0b72009-04-27 21:30:55848#endif
849
initial.commit09911bf2008-07-26 23:55:29850 PrefService* pref = g_browser_process->local_state();
851 DCHECK(pref);
852
[email protected]b58b8b22014-04-08 22:40:33853 pref->SetString(prefs::kStabilityStatsVersion,
854 MetricsLog::GetVersionString());
855 pref->SetInt64(prefs::kStabilityStatsBuildTime, MetricsLog::GetBuildTime());
[email protected]541f77922009-02-23 21:14:38856
initial.commit09911bf2008-07-26 23:55:29857 session_id_ = pref->GetInteger(prefs::kMetricsSessionID);
initial.commit09911bf2008-07-26 23:55:29858
[email protected]c778687a2014-02-11 14:46:45859#if defined(OS_ANDROID)
860 LogAndroidStabilityToPrefs(pref);
861#endif // defined(OS_ANDROID)
862
[email protected]e73c01972008-08-13 00:18:24863 if (!pref->GetBoolean(prefs::kStabilityExitedCleanly)) {
864 IncrementPrefValue(prefs::kStabilityCrashCount);
[email protected]c0c55e92011-09-10 18:47:30865 // Reset flag, and wait until we call LogNeedForCleanShutdown() before
866 // monitoring.
867 pref->SetBoolean(prefs::kStabilityExitedCleanly, true);
[email protected]6a6d0d12013-10-28 15:58:19868
869 // TODO(rtenneti): On windows, consider saving/getting execution_phase from
870 // the registry.
871 int execution_phase = pref->GetInteger(prefs::kStabilityExecutionPhase);
[email protected]6d67ea0d2013-11-14 11:02:21872 UMA_HISTOGRAM_SPARSE_SLOWLY("Chrome.Browser.CrashedExecutionPhase",
[email protected]6a6d0d12013-10-28 15:58:19873 execution_phase);
[email protected]80a8f312013-12-16 18:00:30874
875 // If the previous session didn't exit cleanly, then prepare an initial
876 // stability log if UMA is enabled.
[email protected]39076642014-05-05 20:32:55877 if (state_manager_->IsMetricsReportingEnabled())
[email protected]80a8f312013-12-16 18:00:30878 PrepareInitialStabilityLog();
initial.commit09911bf2008-07-26 23:55:29879 }
[email protected]80a8f312013-12-16 18:00:30880
881 // Update session ID.
882 ++session_id_;
883 pref->SetInteger(prefs::kMetricsSessionID, session_id_);
884
885 // Stability bookkeeping
886 IncrementPrefValue(prefs::kStabilityLaunchCount);
887
[email protected]6d67ea0d2013-11-14 11:02:21888 DCHECK_EQ(UNINITIALIZED_PHASE, execution_phase_);
889 SetExecutionPhase(START_METRICS_RECORDING);
[email protected]e73c01972008-08-13 00:18:24890
[email protected]261ab7c2013-08-19 15:04:58891#if defined(OS_WIN)
892 CountBrowserCrashDumpAttempts();
893#endif // defined(OS_WIN)
894
[email protected]e73c01972008-08-13 00:18:24895 if (!pref->GetBoolean(prefs::kStabilitySessionEndCompleted)) {
896 IncrementPrefValue(prefs::kStabilityIncompleteSessionEndCount);
[email protected]c9abf242009-07-18 06:00:38897 // This is marked false when we get a WM_ENDSESSION.
898 pref->SetBoolean(prefs::kStabilitySessionEndCompleted, true);
initial.commit09911bf2008-07-26 23:55:29899 }
initial.commit09911bf2008-07-26 23:55:29900
[email protected]076961c2014-03-12 22:23:56901 // Call GetUptimes() for the first time, thus allowing all later calls
902 // to record incremental uptimes accurately.
903 base::TimeDelta ignored_uptime_parameter;
904 base::TimeDelta startup_uptime;
905 GetUptimes(pref, &startup_uptime, &ignored_uptime_parameter);
[email protected]c68a2b9b2013-10-09 18:16:36906 DCHECK_EQ(0, startup_uptime.InMicroseconds());
[email protected]9165f742010-03-10 22:55:01907 // For backwards compatibility, leave this intact in case Omaha is checking
908 // them. prefs::kStabilityLastTimestampSec may also be useless now.
909 // TODO(jar): Delete these if they have no uses.
[email protected]0bb1a622009-03-04 03:22:32910 pref->SetInt64(prefs::kStabilityLaunchTimeSec, Time::Now().ToTimeT());
911
912 // Bookkeeping for the uninstall metrics.
913 IncrementLongPrefsValue(prefs::kUninstallLaunchCount);
initial.commit09911bf2008-07-26 23:55:29914
[email protected]92745242009-06-12 16:52:21915 // Get stats on use of command line.
916 const CommandLine* command_line(CommandLine::ForCurrentProcess());
917 size_t common_commands = 0;
918 if (command_line->HasSwitch(switches::kUserDataDir)) {
919 ++common_commands;
920 UMA_HISTOGRAM_COUNTS_100("Chrome.CommandLineDatDirCount", 1);
921 }
922
923 if (command_line->HasSwitch(switches::kApp)) {
924 ++common_commands;
925 UMA_HISTOGRAM_COUNTS_100("Chrome.CommandLineAppModeCount", 1);
926 }
927
[email protected]62b4e522011-07-13 21:46:32928 size_t switch_count = command_line->GetSwitches().size();
929 UMA_HISTOGRAM_COUNTS_100("Chrome.CommandLineFlagCount", switch_count);
[email protected]92745242009-06-12 16:52:21930 UMA_HISTOGRAM_COUNTS_100("Chrome.CommandLineUncommonFlagCount",
[email protected]62b4e522011-07-13 21:46:32931 switch_count - common_commands);
[email protected]92745242009-06-12 16:52:21932
initial.commit09911bf2008-07-26 23:55:29933 // Kick off the process of saving the state (so the uptime numbers keep
934 // getting updated) every n minutes.
935 ScheduleNextStateSave();
936}
937
[email protected]c94d7382012-02-28 08:43:40938// static
[email protected]d33e7cc2011-09-23 01:43:56939void MetricsService::InitTaskGetHardwareClass(
[email protected]c94d7382012-02-28 08:43:40940 base::WeakPtr<MetricsService> self,
[email protected]d33e7cc2011-09-23 01:43:56941 base::MessageLoopProxy* target_loop) {
[email protected]d33e7cc2011-09-23 01:43:56942 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
943
944 std::string hardware_class;
945#if defined(OS_CHROMEOS)
946 chromeos::system::StatisticsProvider::GetInstance()->GetMachineStatistic(
947 "hardware_class", &hardware_class);
948#endif // OS_CHROMEOS
949
950 target_loop->PostTask(FROM_HERE,
951 base::Bind(&MetricsService::OnInitTaskGotHardwareClass,
[email protected]c94d7382012-02-28 08:43:40952 self, hardware_class));
[email protected]d33e7cc2011-09-23 01:43:56953}
954
955void MetricsService::OnInitTaskGotHardwareClass(
956 const std::string& hardware_class) {
[email protected]ed0fd002012-04-25 23:10:34957 DCHECK_EQ(INIT_TASK_SCHEDULED, state_);
[email protected]85ed9d42010-06-08 22:37:44958 hardware_class_ = hardware_class;
[email protected]d33e7cc2011-09-23 01:43:56959
[email protected]ebd71962012-12-20 02:56:55960#if defined(ENABLE_PLUGINS)
[email protected]d33e7cc2011-09-23 01:43:56961 // Start the next part of the init task: loading plugin information.
962 PluginService::GetInstance()->GetPlugins(
963 base::Bind(&MetricsService::OnInitTaskGotPluginInfo,
[email protected]c94d7382012-02-28 08:43:40964 self_ptr_factory_.GetWeakPtr()));
[email protected]ebd71962012-12-20 02:56:55965#else
[email protected]d7bd3e52013-07-21 04:29:20966 std::vector<content::WebPluginInfo> plugin_list_empty;
[email protected]ebd71962012-12-20 02:56:55967 OnInitTaskGotPluginInfo(plugin_list_empty);
968#endif // defined(ENABLE_PLUGINS)
[email protected]d33e7cc2011-09-23 01:43:56969}
970
971void MetricsService::OnInitTaskGotPluginInfo(
[email protected]d7bd3e52013-07-21 04:29:20972 const std::vector<content::WebPluginInfo>& plugins) {
[email protected]ed0fd002012-04-25 23:10:34973 DCHECK_EQ(INIT_TASK_SCHEDULED, state_);
[email protected]35fa6a22009-08-15 00:04:01974 plugins_ = plugins;
[email protected]d33e7cc2011-09-23 01:43:56975
[email protected]197c0772012-05-14 23:50:51976 // Schedules a task on a blocking pool thread to gather Google Update
977 // statistics (requires Registry reads).
978 BrowserThread::PostBlockingPoolTask(
979 FROM_HERE,
980 base::Bind(&MetricsService::InitTaskGetGoogleUpdateData,
981 self_ptr_factory_.GetWeakPtr(),
[email protected]b3a25092013-05-28 22:08:16982 base::MessageLoop::current()->message_loop_proxy()));
[email protected]197c0772012-05-14 23:50:51983}
984
985// static
986void MetricsService::InitTaskGetGoogleUpdateData(
987 base::WeakPtr<MetricsService> self,
988 base::MessageLoopProxy* target_loop) {
989 GoogleUpdateMetrics google_update_metrics;
990
991#if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
992 const bool system_install = GoogleUpdateSettings::IsSystemInstall();
993
994 google_update_metrics.is_system_install = system_install;
995 google_update_metrics.last_started_au =
996 GoogleUpdateSettings::GetGoogleUpdateLastStartedAU(system_install);
997 google_update_metrics.last_checked =
998 GoogleUpdateSettings::GetGoogleUpdateLastChecked(system_install);
999 GoogleUpdateSettings::GetUpdateDetailForGoogleUpdate(
1000 system_install,
1001 &google_update_metrics.google_update_data);
1002 GoogleUpdateSettings::GetUpdateDetail(
1003 system_install,
1004 &google_update_metrics.product_data);
1005#endif // defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
1006
1007 target_loop->PostTask(FROM_HERE,
1008 base::Bind(&MetricsService::OnInitTaskGotGoogleUpdateData,
1009 self, google_update_metrics));
1010}
1011
1012void MetricsService::OnInitTaskGotGoogleUpdateData(
1013 const GoogleUpdateMetrics& google_update_metrics) {
1014 DCHECK_EQ(INIT_TASK_SCHEDULED, state_);
1015
1016 google_update_metrics_ = google_update_metrics;
1017
[email protected]ed0fd002012-04-25 23:10:341018 // Start the next part of the init task: fetching performance data. This will
1019 // call into |FinishedReceivingProfilerData()| when the task completes.
1020 chrome_browser_metrics::TrackingSynchronizer::FetchProfilerDataAsynchronously(
1021 self_ptr_factory_.GetWeakPtr());
1022}
1023
[email protected]dd98f392013-02-04 13:03:221024void MetricsService::OnUserAction(const std::string& action) {
[email protected]e5ad60a2014-03-11 03:54:041025 if (!ShouldLogEvents())
[email protected]dd98f392013-02-04 13:03:221026 return;
1027
[email protected]4426d2d2014-04-09 12:33:001028 log_manager_.current_log()->RecordUserAction(action);
[email protected]dd98f392013-02-04 13:03:221029 HandleIdleSinceLastTransmission(false);
1030}
1031
[email protected]ed0fd002012-04-25 23:10:341032void MetricsService::ReceivedProfilerData(
1033 const tracked_objects::ProcessDataSnapshot& process_data,
[email protected]f3b357692013-03-22 05:16:131034 int process_type) {
[email protected]ed0fd002012-04-25 23:10:341035 DCHECK_EQ(INIT_TASK_SCHEDULED, state_);
1036
1037 // Upon the first callback, create the initial log so that we can immediately
1038 // save the profiler data.
[email protected]9eae4032014-04-09 19:15:191039 if (!initial_metrics_log_.get()) {
1040 initial_metrics_log_.reset(
[email protected]39076642014-05-05 20:32:551041 new MetricsLog(state_manager_->client_id(), session_id_,
1042 MetricsLog::ONGOING_LOG));
[email protected]2a321de32014-05-10 19:59:061043 NotifyOnDidCreateMetricsLog();
[email protected]9eae4032014-04-09 19:15:191044 }
[email protected]ed0fd002012-04-25 23:10:341045
[email protected]80a8f312013-12-16 18:00:301046 initial_metrics_log_->RecordProfilerData(process_data, process_type);
[email protected]ed0fd002012-04-25 23:10:341047}
1048
1049void MetricsService::FinishedReceivingProfilerData() {
1050 DCHECK_EQ(INIT_TASK_SCHEDULED, state_);
[email protected]c68a2b9b2013-10-09 18:16:361051 state_ = INIT_TASK_DONE;
[email protected]70886cd2013-12-04 05:53:421052 scheduler_->InitTaskComplete();
[email protected]c68a2b9b2013-10-09 18:16:361053}
1054
[email protected]076961c2014-03-12 22:23:561055void MetricsService::GetUptimes(PrefService* pref,
1056 base::TimeDelta* incremental_uptime,
1057 base::TimeDelta* uptime) {
[email protected]c68a2b9b2013-10-09 18:16:361058 base::TimeTicks now = base::TimeTicks::Now();
[email protected]076961c2014-03-12 22:23:561059 // If this is the first call, init |first_updated_time_| and
1060 // |last_updated_time_|.
1061 if (last_updated_time_.is_null()) {
1062 first_updated_time_ = now;
[email protected]c68a2b9b2013-10-09 18:16:361063 last_updated_time_ = now;
[email protected]076961c2014-03-12 22:23:561064 }
1065 *incremental_uptime = now - last_updated_time_;
1066 *uptime = now - first_updated_time_;
[email protected]c68a2b9b2013-10-09 18:16:361067 last_updated_time_ = now;
1068
[email protected]076961c2014-03-12 22:23:561069 const int64 incremental_time_secs = incremental_uptime->InSeconds();
[email protected]c68a2b9b2013-10-09 18:16:361070 if (incremental_time_secs > 0) {
1071 int64 metrics_uptime = pref->GetInt64(prefs::kUninstallMetricsUptimeSec);
1072 metrics_uptime += incremental_time_secs;
1073 pref->SetInt64(prefs::kUninstallMetricsUptimeSec, metrics_uptime);
1074 }
initial.commit09911bf2008-07-26 23:55:291075}
1076
[email protected]2a321de32014-05-10 19:59:061077void MetricsService::AddObserver(MetricsServiceObserver* observer) {
1078 DCHECK(thread_checker_.CalledOnValidThread());
1079 observers_.AddObserver(observer);
1080}
1081
1082void MetricsService::RemoveObserver(MetricsServiceObserver* observer) {
1083 DCHECK(thread_checker_.CalledOnValidThread());
1084 observers_.RemoveObserver(observer);
1085}
1086
1087void MetricsService::NotifyOnDidCreateMetricsLog() {
1088 DCHECK(thread_checker_.CalledOnValidThread());
1089 FOR_EACH_OBSERVER(
1090 MetricsServiceObserver, observers_, OnDidCreateMetricsLog());
1091}
1092
initial.commit09911bf2008-07-26 23:55:291093//------------------------------------------------------------------------------
1094// State save methods
1095
1096void MetricsService::ScheduleNextStateSave() {
[email protected]8454aeb2011-11-19 23:38:201097 state_saver_factory_.InvalidateWeakPtrs();
initial.commit09911bf2008-07-26 23:55:291098
[email protected]b3a25092013-05-28 22:08:161099 base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
[email protected]8454aeb2011-11-19 23:38:201100 base::Bind(&MetricsService::SaveLocalState,
1101 state_saver_factory_.GetWeakPtr()),
[email protected]fc4252a72012-01-12 21:58:471102 base::TimeDelta::FromMinutes(kSaveStateIntervalMinutes));
initial.commit09911bf2008-07-26 23:55:291103}
1104
1105void MetricsService::SaveLocalState() {
1106 PrefService* pref = g_browser_process->local_state();
1107 if (!pref) {
[email protected]a063c102010-07-22 22:20:191108 NOTREACHED();
initial.commit09911bf2008-07-26 23:55:291109 return;
1110 }
1111
1112 RecordCurrentState(pref);
initial.commit09911bf2008-07-26 23:55:291113
[email protected]fc4252a72012-01-12 21:58:471114 // TODO(jar):110021 Does this run down the batteries????
initial.commit09911bf2008-07-26 23:55:291115 ScheduleNextStateSave();
1116}
1117
1118
1119//------------------------------------------------------------------------------
1120// Recording control methods
1121
[email protected]410938e02012-10-24 16:33:591122void MetricsService::OpenNewLog() {
1123 DCHECK(!log_manager_.current_log());
initial.commit09911bf2008-07-26 23:55:291124
[email protected]9eae4032014-04-09 19:15:191125 log_manager_.BeginLoggingWithLog(
[email protected]39076642014-05-05 20:32:551126 new MetricsLog(state_manager_->client_id(), session_id_,
1127 MetricsLog::ONGOING_LOG));
[email protected]2a321de32014-05-10 19:59:061128 NotifyOnDidCreateMetricsLog();
initial.commit09911bf2008-07-26 23:55:291129 if (state_ == INITIALIZED) {
1130 // We only need to schedule that run once.
[email protected]85ed9d42010-06-08 22:37:441131 state_ = INIT_TASK_SCHEDULED;
initial.commit09911bf2008-07-26 23:55:291132
[email protected]85ed9d42010-06-08 22:37:441133 // Schedules a task on the file thread for execution of slower
1134 // initialization steps (such as plugin list generation) necessary
1135 // for sending the initial log. This avoids blocking the main UI
1136 // thread.
[email protected]ed10dd12011-12-07 12:03:421137 BrowserThread::PostDelayedTask(
1138 BrowserThread::FILE,
1139 FROM_HERE,
[email protected]d33e7cc2011-09-23 01:43:561140 base::Bind(&MetricsService::InitTaskGetHardwareClass,
[email protected]c94d7382012-02-28 08:43:401141 self_ptr_factory_.GetWeakPtr(),
[email protected]b3a25092013-05-28 22:08:161142 base::MessageLoop::current()->message_loop_proxy()),
[email protected]7e560102012-03-08 20:58:421143 base::TimeDelta::FromSeconds(kInitializationDelaySeconds));
initial.commit09911bf2008-07-26 23:55:291144 }
1145}
1146
[email protected]410938e02012-10-24 16:33:591147void MetricsService::CloseCurrentLog() {
[email protected]cac267c2011-09-29 15:18:101148 if (!log_manager_.current_log())
initial.commit09911bf2008-07-26 23:55:291149 return;
1150
[email protected]68475e602008-08-22 03:21:151151 // TODO(jar): Integrate bounds on log recording more consistently, so that we
1152 // can stop recording logs that are too big much sooner.
[email protected]cac267c2011-09-29 15:18:101153 if (log_manager_.current_log()->num_events() > kEventLimit) {
[email protected]553dba62009-02-24 19:08:231154 UMA_HISTOGRAM_COUNTS("UMA.Discarded Log Events",
[email protected]cac267c2011-09-29 15:18:101155 log_manager_.current_log()->num_events());
1156 log_manager_.DiscardCurrentLog();
[email protected]410938e02012-10-24 16:33:591157 OpenNewLog(); // Start trivial log to hold our histograms.
[email protected]68475e602008-08-22 03:21:151158 }
1159
[email protected]cac267c2011-09-29 15:18:101160 // Adds to ongoing logs.
1161 log_manager_.current_log()->set_hardware_class(hardware_class_);
[email protected]accdfa62011-09-20 01:56:521162
[email protected]0b33f80b2008-12-17 21:34:361163 // Put incremental data (histogram deltas, and realtime stats deltas) at the
[email protected]147bbc0b2009-01-06 19:37:401164 // end of all log transmissions (initial log handles this separately).
[email protected]024b5cd2011-05-27 03:29:381165 // RecordIncrementalStabilityElements only exists on the derived
1166 // MetricsLog class.
[email protected]279703f2012-01-20 22:23:261167 MetricsLog* current_log =
1168 static_cast<MetricsLog*>(log_manager_.current_log());
[email protected]024b5cd2011-05-27 03:29:381169 DCHECK(current_log);
[email protected]60677562013-11-17 15:52:551170 std::vector<chrome_variations::ActiveGroupId> synthetic_trials;
1171 GetCurrentSyntheticFieldTrials(&synthetic_trials);
[email protected]0edf8762013-11-21 18:33:301172 current_log->RecordEnvironment(plugins_, google_update_metrics_,
1173 synthetic_trials);
[email protected]c68a2b9b2013-10-09 18:16:361174 PrefService* pref = g_browser_process->local_state();
[email protected]076961c2014-03-12 22:23:561175 base::TimeDelta incremental_uptime;
1176 base::TimeDelta uptime;
1177 GetUptimes(pref, &incremental_uptime, &uptime);
[email protected]9eae4032014-04-09 19:15:191178 current_log->RecordStabilityMetrics(incremental_uptime, uptime);
[email protected]60677562013-11-17 15:52:551179
[email protected]024b5cd2011-05-27 03:29:381180 RecordCurrentHistograms();
initial.commit09911bf2008-07-26 23:55:291181
[email protected]29948262012-03-01 12:15:081182 log_manager_.FinishCurrentLog();
initial.commit09911bf2008-07-26 23:55:291183}
1184
[email protected]cac267c2011-09-29 15:18:101185void MetricsService::PushPendingLogsToPersistentStorage() {
[email protected]80a8f312013-12-16 18:00:301186 if (state_ < SENDING_INITIAL_STABILITY_LOG)
[email protected]28ab7f92009-01-06 21:39:041187 return; // We didn't and still don't have time to get plugin list etc.
initial.commit09911bf2008-07-26 23:55:291188
[email protected]cac267c2011-09-29 15:18:101189 if (log_manager_.has_staged_log()) {
[email protected]7d41ae6d2012-06-26 08:53:031190 // We may race here, and send second copy of the log later.
[email protected]dc61fe92012-06-12 00:13:501191 MetricsLogManager::StoreType store_type;
[email protected]e3eb0c42013-04-18 06:18:581192 if (current_fetch_.get())
[email protected]dc61fe92012-06-12 00:13:501193 store_type = MetricsLogManager::PROVISIONAL_STORE;
1194 else
1195 store_type = MetricsLogManager::NORMAL_STORE;
[email protected]e7508d82012-05-03 15:59:531196 log_manager_.StoreStagedLogAsUnsent(store_type);
initial.commit09911bf2008-07-26 23:55:291197 }
[email protected]cac267c2011-09-29 15:18:101198 DCHECK(!log_manager_.has_staged_log());
[email protected]410938e02012-10-24 16:33:591199 CloseCurrentLog();
[email protected]80a8f312013-12-16 18:00:301200 log_manager_.PersistUnsentLogs();
[email protected]7d41ae6d2012-06-26 08:53:031201
1202 // If there was a staged and/or current log, then there is now at least one
1203 // log waiting to be uploaded.
1204 if (log_manager_.has_unsent_logs())
1205 state_ = SENDING_OLD_LOGS;
initial.commit09911bf2008-07-26 23:55:291206}
1207
1208//------------------------------------------------------------------------------
1209// Transmission of logs methods
1210
[email protected]7f7f1962011-04-20 15:58:161211void MetricsService::StartSchedulerIfNecessary() {
[email protected]410938e02012-10-24 16:33:591212 // Never schedule cutting or uploading of logs in test mode.
1213 if (test_mode_active_)
1214 return;
1215
1216 // Even if reporting is disabled, the scheduler is needed to trigger the
1217 // creation of the initial log, which must be done in order for any logs to be
1218 // persisted on shutdown or backgrounding.
[email protected]80a8f312013-12-16 18:00:301219 if (recording_active() &&
1220 (reporting_active() || state_ < SENDING_INITIAL_STABILITY_LOG)) {
[email protected]7f7f1962011-04-20 15:58:161221 scheduler_->Start();
[email protected]80a8f312013-12-16 18:00:301222 }
initial.commit09911bf2008-07-26 23:55:291223}
1224
[email protected]7f7f1962011-04-20 15:58:161225void MetricsService::StartScheduledUpload() {
[email protected]cd1ac712012-06-26 08:26:471226 // If we're getting no notifications, then the log won't have much in it, and
1227 // it's possible the computer is about to go to sleep, so don't upload and
1228 // stop the scheduler.
[email protected]410938e02012-10-24 16:33:591229 // If recording has been turned off, the scheduler doesn't need to run.
1230 // If reporting is off, proceed if the initial log hasn't been created, since
1231 // that has to happen in order for logs to be cut and stored when persisting.
[email protected]cd1ac712012-06-26 08:26:471232 // TODO(stuartmorgan): Call Stop() on the schedule when reporting and/or
1233 // recording are turned off instead of letting it fire and then aborting.
1234 if (idle_since_last_transmission_ ||
[email protected]410938e02012-10-24 16:33:591235 !recording_active() ||
[email protected]80a8f312013-12-16 18:00:301236 (!reporting_active() && state_ >= SENDING_INITIAL_STABILITY_LOG)) {
[email protected]7f7f1962011-04-20 15:58:161237 scheduler_->Stop();
1238 scheduler_->UploadCancelled();
1239 return;
1240 }
1241
[email protected]c15faf372012-07-11 06:01:341242 // If the callback was to upload an old log, but there no longer is one,
1243 // just report success back to the scheduler to begin the ongoing log
1244 // callbacks.
1245 // TODO(stuartmorgan): Consider removing the distinction between
1246 // SENDING_OLD_LOGS and SENDING_CURRENT_LOGS to simplify the state machine
1247 // now that the log upload flow is the same for both modes.
1248 if (state_ == SENDING_OLD_LOGS && !log_manager_.has_unsent_logs()) {
1249 state_ = SENDING_CURRENT_LOGS;
1250 scheduler_->UploadFinished(true /* healthy */, false /* no unsent logs */);
1251 return;
1252 }
[email protected]cd1ac712012-06-26 08:26:471253 // If there are unsent logs, send the next one. If not, start the asynchronous
1254 // process of finalizing the current log for upload.
1255 if (state_ == SENDING_OLD_LOGS) {
1256 DCHECK(log_manager_.has_unsent_logs());
1257 log_manager_.StageNextLogForUpload();
1258 SendStagedLog();
1259 } else {
1260 StartFinalLogInfoCollection();
1261 }
[email protected]29948262012-03-01 12:15:081262}
1263
1264void MetricsService::StartFinalLogInfoCollection() {
1265 // Begin the multi-step process of collecting memory usage histograms:
1266 // First spawn a task to collect the memory details; when that task is
1267 // finished, it will call OnMemoryDetailCollectionDone. That will in turn
1268 // call HistogramSynchronization to collect histograms from all renderers and
1269 // then call OnHistogramSynchronizationDone to continue processing.
[email protected]d119f222012-06-08 02:33:271270 DCHECK(!waiting_for_asynchronous_reporting_step_);
1271 waiting_for_asynchronous_reporting_step_ = true;
[email protected]7f7f1962011-04-20 15:58:161272
[email protected]2226c222011-11-22 00:08:401273 base::Closure callback =
1274 base::Bind(&MetricsService::OnMemoryDetailCollectionDone,
[email protected]c94d7382012-02-28 08:43:401275 self_ptr_factory_.GetWeakPtr());
[email protected]84c988a2011-04-19 17:56:331276
[email protected]2226c222011-11-22 00:08:401277 scoped_refptr<MetricsMemoryDetails> details(
1278 new MetricsMemoryDetails(callback));
[email protected]4306df72012-04-20 18:58:571279 details->StartFetch(MemoryDetails::UPDATE_USER_METRICS);
[email protected]84c988a2011-04-19 17:56:331280
1281 // Collect WebCore cache information to put into a histogram.
[email protected]f3b1a082011-11-18 00:34:301282 for (content::RenderProcessHost::iterator i(
1283 content::RenderProcessHost::AllHostsIterator());
[email protected]84c988a2011-04-19 17:56:331284 !i.IsAtEnd(); i.Advance())
[email protected]2ccf45c2011-08-19 23:35:501285 i.GetCurrentValue()->Send(new ChromeViewMsg_GetCacheResourceStats());
[email protected]84c988a2011-04-19 17:56:331286}
1287
1288void MetricsService::OnMemoryDetailCollectionDone() {
[email protected]c9a3ef82009-05-28 22:02:461289 DCHECK(IsSingleThreaded());
[email protected]7f7f1962011-04-20 15:58:161290 // This function should only be called as the callback from an ansynchronous
1291 // step.
[email protected]d119f222012-06-08 02:33:271292 DCHECK(waiting_for_asynchronous_reporting_step_);
[email protected]c9a3ef82009-05-28 22:02:461293
[email protected]c9a3ef82009-05-28 22:02:461294 // Create a callback_task for OnHistogramSynchronizationDone.
[email protected]2226c222011-11-22 00:08:401295 base::Closure callback = base::Bind(
1296 &MetricsService::OnHistogramSynchronizationDone,
[email protected]c94d7382012-02-28 08:43:401297 self_ptr_factory_.GetWeakPtr());
[email protected]c9a3ef82009-05-28 22:02:461298
[email protected]a3079832013-10-24 20:29:361299 base::TimeDelta timeout =
1300 base::TimeDelta::FromMilliseconds(kMaxHistogramGatheringWaitDuration);
1301
1302 DCHECK_EQ(num_async_histogram_fetches_in_progress_, 0);
1303
1304#if defined(OS_ANDROID)
1305 // Android has no service process.
1306 num_async_histogram_fetches_in_progress_ = 1;
1307#else // OS_ANDROID
1308 num_async_histogram_fetches_in_progress_ = 2;
1309 // Run requests to service and content in parallel.
1310 if (!ServiceProcessControl::GetInstance()->GetHistograms(callback, timeout)) {
1311 // Assume |num_async_histogram_fetches_in_progress_| is not changed by
1312 // |GetHistograms()|.
1313 DCHECK_EQ(num_async_histogram_fetches_in_progress_, 2);
1314 // Assign |num_async_histogram_fetches_in_progress_| above and decrement it
1315 // here to make code work even if |GetHistograms()| fired |callback|.
1316 --num_async_histogram_fetches_in_progress_;
1317 }
1318#endif // OS_ANDROID
1319
[email protected]c9a3ef82009-05-28 22:02:461320 // Set up the callback to task to call after we receive histograms from all
[email protected]83ab4a282012-07-12 18:19:451321 // child processes. Wait time specifies how long to wait before absolutely
[email protected]c9a3ef82009-05-28 22:02:461322 // calling us back on the task.
[email protected]a3079832013-10-24 20:29:361323 content::FetchHistogramsAsynchronously(base::MessageLoop::current(), callback,
1324 timeout);
[email protected]c9a3ef82009-05-28 22:02:461325}
1326
1327void MetricsService::OnHistogramSynchronizationDone() {
initial.commit09911bf2008-07-26 23:55:291328 DCHECK(IsSingleThreaded());
[email protected]29948262012-03-01 12:15:081329 // This function should only be called as the callback from an ansynchronous
1330 // step.
[email protected]d119f222012-06-08 02:33:271331 DCHECK(waiting_for_asynchronous_reporting_step_);
[email protected]a3079832013-10-24 20:29:361332 DCHECK_GT(num_async_histogram_fetches_in_progress_, 0);
1333
1334 // Check if all expected requests finished.
1335 if (--num_async_histogram_fetches_in_progress_ > 0)
1336 return;
initial.commit09911bf2008-07-26 23:55:291337
[email protected]d119f222012-06-08 02:33:271338 waiting_for_asynchronous_reporting_step_ = false;
[email protected]29948262012-03-01 12:15:081339 OnFinalLogInfoCollectionDone();
1340}
1341
1342void MetricsService::OnFinalLogInfoCollectionDone() {
[email protected]7f7f1962011-04-20 15:58:161343 // If somehow there is a fetch in progress, we return and hope things work
1344 // out. The scheduler isn't informed since if this happens, the scheduler
1345 // will get a response from the upload.
[email protected]e3eb0c42013-04-18 06:18:581346 DCHECK(!current_fetch_.get());
1347 if (current_fetch_.get())
[email protected]7f7f1962011-04-20 15:58:161348 return;
1349
[email protected]cd1ac712012-06-26 08:26:471350 // Abort if metrics were turned off during the final info gathering.
[email protected]410938e02012-10-24 16:33:591351 if (!recording_active()) {
[email protected]7f7f1962011-04-20 15:58:161352 scheduler_->Stop();
1353 scheduler_->UploadCancelled();
[email protected]d01b8732008-10-16 02:18:071354 return;
1355 }
1356
[email protected]cd1ac712012-06-26 08:26:471357 StageNewLog();
[email protected]410938e02012-10-24 16:33:591358
1359 // If logs shouldn't be uploaded, stop here. It's important that this check
1360 // be after StageNewLog(), otherwise the previous logs will never be loaded,
1361 // and thus the open log won't be persisted.
1362 // TODO(stuartmorgan): This is unnecessarily complicated; restructure loading
1363 // of previous logs to not require running part of the upload logic.
1364 // http://crbug.com/157337
1365 if (!reporting_active()) {
1366 scheduler_->Stop();
1367 scheduler_->UploadCancelled();
1368 return;
1369 }
1370
[email protected]29948262012-03-01 12:15:081371 SendStagedLog();
1372}
1373
[email protected]cd1ac712012-06-26 08:26:471374void MetricsService::StageNewLog() {
[email protected]29948262012-03-01 12:15:081375 if (log_manager_.has_staged_log())
1376 return;
1377
1378 switch (state_) {
1379 case INITIALIZED:
1380 case INIT_TASK_SCHEDULED: // We should be further along by now.
[email protected]dc61fe92012-06-12 00:13:501381 NOTREACHED();
[email protected]29948262012-03-01 12:15:081382 return;
1383
1384 case INIT_TASK_DONE:
[email protected]80a8f312013-12-16 18:00:301385 if (has_initial_stability_log_) {
1386 // There's an initial stability log, ready to send.
1387 log_manager_.StageNextLogForUpload();
1388 has_initial_stability_log_ = false;
[email protected]f61eb842014-01-22 10:59:131389 // Note: No need to call LoadPersistedUnsentLogs() here because unsent
1390 // logs have already been loaded by PrepareInitialStabilityLog().
[email protected]80a8f312013-12-16 18:00:301391 state_ = SENDING_INITIAL_STABILITY_LOG;
1392 } else {
[email protected]b58b8b22014-04-08 22:40:331393 PrepareInitialMetricsLog();
[email protected]f61eb842014-01-22 10:59:131394 // Load unsent logs (if any) from local state.
1395 log_manager_.LoadPersistedUnsentLogs();
[email protected]80a8f312013-12-16 18:00:301396 state_ = SENDING_INITIAL_METRICS_LOG;
1397 }
[email protected]29948262012-03-01 12:15:081398 break;
1399
1400 case SENDING_OLD_LOGS:
[email protected]cd1ac712012-06-26 08:26:471401 NOTREACHED(); // Shouldn't be staging a new log during old log sending.
1402 return;
[email protected]29948262012-03-01 12:15:081403
1404 case SENDING_CURRENT_LOGS:
[email protected]410938e02012-10-24 16:33:591405 CloseCurrentLog();
1406 OpenNewLog();
[email protected]29948262012-03-01 12:15:081407 log_manager_.StageNextLogForUpload();
1408 break;
1409
1410 default:
1411 NOTREACHED();
1412 return;
1413 }
1414
1415 DCHECK(log_manager_.has_staged_log());
1416}
1417
[email protected]80a8f312013-12-16 18:00:301418void MetricsService::PrepareInitialStabilityLog() {
1419 DCHECK_EQ(INITIALIZED, state_);
1420 PrefService* pref = g_browser_process->local_state();
1421 DCHECK_NE(0, pref->GetInteger(prefs::kStabilityCrashCount));
[email protected]29948262012-03-01 12:15:081422
[email protected]80a8f312013-12-16 18:00:301423 scoped_ptr<MetricsLog> initial_stability_log(
[email protected]39076642014-05-05 20:32:551424 new MetricsLog(state_manager_->client_id(), session_id_,
[email protected]9eae4032014-04-09 19:15:191425 MetricsLog::INITIAL_STABILITY_LOG));
[email protected]2a321de32014-05-10 19:59:061426
1427 // Do not call NotifyOnDidCreateMetricsLog here because the stability
1428 // log describes stats from the _previous_ session.
1429
[email protected]80a8f312013-12-16 18:00:301430 if (!initial_stability_log->LoadSavedEnvironmentFromPrefs())
1431 return;
[email protected]9eae4032014-04-09 19:15:191432 initial_stability_log->RecordStabilityMetrics(base::TimeDelta(),
1433 base::TimeDelta());
[email protected]80a8f312013-12-16 18:00:301434 log_manager_.LoadPersistedUnsentLogs();
1435
1436 log_manager_.PauseCurrentLog();
[email protected]9eae4032014-04-09 19:15:191437 log_manager_.BeginLoggingWithLog(initial_stability_log.release());
[email protected]c778687a2014-02-11 14:46:451438#if defined(OS_ANDROID)
1439 ConvertAndroidStabilityPrefsToHistograms(pref);
1440 RecordCurrentStabilityHistograms();
1441#endif // defined(OS_ANDROID)
[email protected]80a8f312013-12-16 18:00:301442 log_manager_.FinishCurrentLog();
1443 log_manager_.ResumePausedLog();
1444
1445 // Store unsent logs, including the stability log that was just saved, so
1446 // that they're not lost in case of a crash before upload time.
1447 log_manager_.PersistUnsentLogs();
1448
1449 has_initial_stability_log_ = true;
1450}
1451
[email protected]b58b8b22014-04-08 22:40:331452void MetricsService::PrepareInitialMetricsLog() {
[email protected]80a8f312013-12-16 18:00:301453 DCHECK(state_ == INIT_TASK_DONE || state_ == SENDING_INITIAL_STABILITY_LOG);
1454 initial_metrics_log_->set_hardware_class(hardware_class_);
[email protected]0edf8762013-11-21 18:33:301455
[email protected]60677562013-11-17 15:52:551456 std::vector<chrome_variations::ActiveGroupId> synthetic_trials;
1457 GetCurrentSyntheticFieldTrials(&synthetic_trials);
[email protected]80a8f312013-12-16 18:00:301458 initial_metrics_log_->RecordEnvironment(plugins_, google_update_metrics_,
1459 synthetic_trials);
[email protected]0edf8762013-11-21 18:33:301460 PrefService* pref = g_browser_process->local_state();
[email protected]076961c2014-03-12 22:23:561461 base::TimeDelta incremental_uptime;
1462 base::TimeDelta uptime;
1463 GetUptimes(pref, &incremental_uptime, &uptime);
[email protected]9eae4032014-04-09 19:15:191464 initial_metrics_log_->RecordStabilityMetrics(incremental_uptime, uptime);
[email protected]29948262012-03-01 12:15:081465
1466 // Histograms only get written to the current log, so make the new log current
1467 // before writing them.
1468 log_manager_.PauseCurrentLog();
[email protected]9eae4032014-04-09 19:15:191469 log_manager_.BeginLoggingWithLog(initial_metrics_log_.release());
[email protected]c778687a2014-02-11 14:46:451470#if defined(OS_ANDROID)
1471 ConvertAndroidStabilityPrefsToHistograms(pref);
1472#endif // defined(OS_ANDROID)
[email protected]29948262012-03-01 12:15:081473 RecordCurrentHistograms();
1474 log_manager_.FinishCurrentLog();
1475 log_manager_.ResumePausedLog();
1476
1477 DCHECK(!log_manager_.has_staged_log());
1478 log_manager_.StageNextLogForUpload();
1479}
1480
[email protected]29948262012-03-01 12:15:081481void MetricsService::SendStagedLog() {
1482 DCHECK(log_manager_.has_staged_log());
1483
[email protected]cac267c2011-09-29 15:18:101484 PrepareFetchWithStagedLog();
[email protected]d01b8732008-10-16 02:18:071485
[email protected]e3eb0c42013-04-18 06:18:581486 bool upload_created = (current_fetch_.get() != NULL);
[email protected]d6bebb92012-06-13 23:14:551487 UMA_HISTOGRAM_BOOLEAN("UMA.UploadCreation", upload_created);
1488 if (!upload_created) {
[email protected]d01b8732008-10-16 02:18:071489 // Compression failed, and log discarded :-/.
[email protected]dc61fe92012-06-12 00:13:501490 // Skip this upload and hope things work out next time.
[email protected]cac267c2011-09-29 15:18:101491 log_manager_.DiscardStagedLog();
[email protected]7f7f1962011-04-20 15:58:161492 scheduler_->UploadCancelled();
[email protected]d01b8732008-10-16 02:18:071493 return;
1494 }
1495
[email protected]d119f222012-06-08 02:33:271496 DCHECK(!waiting_for_asynchronous_reporting_step_);
[email protected]d119f222012-06-08 02:33:271497 waiting_for_asynchronous_reporting_step_ = true;
[email protected]dc61fe92012-06-12 00:13:501498
[email protected]e3eb0c42013-04-18 06:18:581499 current_fetch_->Start();
[email protected]d01b8732008-10-16 02:18:071500
1501 HandleIdleSinceLastTransmission(true);
1502}
1503
[email protected]cac267c2011-09-29 15:18:101504void MetricsService::PrepareFetchWithStagedLog() {
[email protected]dc61fe92012-06-12 00:13:501505 DCHECK(log_manager_.has_staged_log());
[email protected]cac78842008-11-27 01:02:201506
[email protected]fe58acc22012-02-29 01:29:581507 // Prepare the protobuf version.
[email protected]e3eb0c42013-04-18 06:18:581508 DCHECK(!current_fetch_.get());
[email protected]5f3e1642013-05-05 03:37:341509 if (log_manager_.has_staged_log()) {
[email protected]e3eb0c42013-04-18 06:18:581510 current_fetch_.reset(net::URLFetcher::Create(
[email protected]5f3e1642013-05-05 03:37:341511 GURL(kServerUrl), net::URLFetcher::POST, this));
[email protected]e3eb0c42013-04-18 06:18:581512 current_fetch_->SetRequestContext(
[email protected]fe58acc22012-02-29 01:29:581513 g_browser_process->system_request_context());
[email protected]537c638d2013-07-04 00:49:191514
[email protected]8df71322013-09-13 18:40:001515 std::string log_text = log_manager_.staged_log_text();
1516 std::string compressed_log_text;
1517 bool compression_successful = chrome::GzipCompress(log_text,
1518 &compressed_log_text);
1519 DCHECK(compression_successful);
1520 if (compression_successful) {
1521 current_fetch_->SetUploadData(kMimeType, compressed_log_text);
1522 // Tell the server that we're uploading gzipped protobufs.
1523 current_fetch_->SetExtraRequestHeaders("content-encoding: gzip");
[email protected]cfee9aa52013-10-19 17:53:051524 const std::string hash =
1525 base::HexEncode(log_manager_.staged_log_hash().data(),
1526 log_manager_.staged_log_hash().size());
1527 DCHECK(!hash.empty());
1528 current_fetch_->AddExtraRequestHeader("X-Chrome-UMA-Log-SHA1: " + hash);
[email protected]8df71322013-09-13 18:40:001529 UMA_HISTOGRAM_PERCENTAGE(
1530 "UMA.ProtoCompressionRatio",
1531 100 * compressed_log_text.size() / log_text.size());
1532 UMA_HISTOGRAM_CUSTOM_COUNTS(
1533 "UMA.ProtoGzippedKBSaved",
1534 (log_text.size() - compressed_log_text.size()) / 1024,
1535 1, 2000, 50);
[email protected]537c638d2013-07-04 00:49:191536 }
[email protected]537c638d2013-07-04 00:49:191537
[email protected]fe58acc22012-02-29 01:29:581538 // We already drop cookies server-side, but we might as well strip them out
1539 // client-side as well.
[email protected]e3eb0c42013-04-18 06:18:581540 current_fetch_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES |
1541 net::LOAD_DO_NOT_SEND_COOKIES);
[email protected]fe58acc22012-02-29 01:29:581542 }
initial.commit09911bf2008-07-26 23:55:291543}
1544
[email protected]10c2d692012-05-11 05:32:231545void MetricsService::OnURLFetchComplete(const net::URLFetcher* source) {
[email protected]d119f222012-06-08 02:33:271546 DCHECK(waiting_for_asynchronous_reporting_step_);
[email protected]fe58acc22012-02-29 01:29:581547
1548 // We're not allowed to re-use the existing |URLFetcher|s, so free them here.
[email protected]e3eb0c42013-04-18 06:18:581549 // Note however that |source| is aliased to the fetcher, so we should be
[email protected]4266def22012-05-17 01:02:401550 // careful not to delete it too early.
[email protected]e3eb0c42013-04-18 06:18:581551 DCHECK_EQ(current_fetch_.get(), source);
1552 scoped_ptr<net::URLFetcher> s(current_fetch_.Pass());
[email protected]fe58acc22012-02-29 01:29:581553
[email protected]dc61fe92012-06-12 00:13:501554 int response_code = source->GetResponseCode();
[email protected]fe58acc22012-02-29 01:29:581555
[email protected]dc61fe92012-06-12 00:13:501556 // Log a histogram to track response success vs. failure rates.
[email protected]e3eb0c42013-04-18 06:18:581557 UMA_HISTOGRAM_ENUMERATION("UMA.UploadResponseStatus.Protobuf",
1558 ResponseCodeToStatus(response_code),
1559 NUM_RESPONSE_STATUSES);
[email protected]fe58acc22012-02-29 01:29:581560
[email protected]e7508d82012-05-03 15:59:531561 // If the upload was provisionally stored, drop it now that the upload is
1562 // known to have gone through.
1563 log_manager_.DiscardLastProvisionalStore();
initial.commit09911bf2008-07-26 23:55:291564
[email protected]dc61fe92012-06-12 00:13:501565 bool upload_succeeded = response_code == 200;
[email protected]7f7f1962011-04-20 15:58:161566
[email protected]0eb34fee2009-01-21 08:04:381567 // Provide boolean for error recovery (allow us to ignore response_code).
[email protected]dc6f4962009-02-13 01:25:501568 bool discard_log = false;
[email protected]5f3e1642013-05-05 03:37:341569 const size_t log_size = log_manager_.staged_log_text().length();
[email protected]dc61fe92012-06-12 00:13:501570 if (!upload_succeeded && log_size > kUploadLogAvoidRetransmitSize) {
1571 UMA_HISTOGRAM_COUNTS("UMA.Large Rejected Log was Discarded",
1572 static_cast<int>(log_size));
[email protected]0eb34fee2009-01-21 08:04:381573 discard_log = true;
[email protected]dc61fe92012-06-12 00:13:501574 } else if (response_code == 400) {
[email protected]0eb34fee2009-01-21 08:04:381575 // Bad syntax. Retransmission won't work.
[email protected]0eb34fee2009-01-21 08:04:381576 discard_log = true;
[email protected]68475e602008-08-22 03:21:151577 }
1578
[email protected]e3eb0c42013-04-18 06:18:581579 if (upload_succeeded || discard_log)
[email protected]5f3e1642013-05-05 03:37:341580 log_manager_.DiscardStagedLog();
[email protected]dc61fe92012-06-12 00:13:501581
1582 waiting_for_asynchronous_reporting_step_ = false;
1583
1584 if (!log_manager_.has_staged_log()) {
initial.commit09911bf2008-07-26 23:55:291585 switch (state_) {
[email protected]80a8f312013-12-16 18:00:301586 case SENDING_INITIAL_STABILITY_LOG:
1587 // Store the updated list to disk now that the removed log is uploaded.
1588 log_manager_.PersistUnsentLogs();
[email protected]b58b8b22014-04-08 22:40:331589 PrepareInitialMetricsLog();
[email protected]80a8f312013-12-16 18:00:301590 SendStagedLog();
1591 state_ = SENDING_INITIAL_METRICS_LOG;
1592 break;
1593
1594 case SENDING_INITIAL_METRICS_LOG:
1595 // The initial metrics log never gets persisted to local state, so it's
1596 // not necessary to call log_manager_.PersistUnsentLogs() here.
1597 // TODO(asvitkine): It should be persisted like the initial stability
1598 // log and old unsent logs. http://crbug.com/328417
[email protected]cd1ac712012-06-26 08:26:471599 state_ = log_manager_.has_unsent_logs() ? SENDING_OLD_LOGS
1600 : SENDING_CURRENT_LOGS;
initial.commit09911bf2008-07-26 23:55:291601 break;
1602
initial.commit09911bf2008-07-26 23:55:291603 case SENDING_OLD_LOGS:
[email protected]d53e2232011-06-30 15:54:571604 // Store the updated list to disk now that the removed log is uploaded.
[email protected]80a8f312013-12-16 18:00:301605 log_manager_.PersistUnsentLogs();
[email protected]cd1ac712012-06-26 08:26:471606 if (!log_manager_.has_unsent_logs())
1607 state_ = SENDING_CURRENT_LOGS;
initial.commit09911bf2008-07-26 23:55:291608 break;
1609
1610 case SENDING_CURRENT_LOGS:
1611 break;
1612
1613 default:
[email protected]a063c102010-07-22 22:20:191614 NOTREACHED();
initial.commit09911bf2008-07-26 23:55:291615 break;
1616 }
[email protected]d01b8732008-10-16 02:18:071617
[email protected]cac267c2011-09-29 15:18:101618 if (log_manager_.has_unsent_logs())
[email protected]ed0fd002012-04-25 23:10:341619 DCHECK_LT(state_, SENDING_CURRENT_LOGS);
initial.commit09911bf2008-07-26 23:55:291620 }
[email protected]252873ef2008-08-04 21:59:451621
[email protected]7f7f1962011-04-20 15:58:161622 // Error 400 indicates a problem with the log, not with the server, so
1623 // don't consider that a sign that the server is in trouble.
[email protected]dc61fe92012-06-12 00:13:501624 bool server_is_healthy = upload_succeeded || response_code == 400;
[email protected]80a8f312013-12-16 18:00:301625 // Don't notify the scheduler that the upload is finished if we've only sent
1626 // the initial stability log, but not yet the initial metrics log (treat the
1627 // two as a single unit of work as far as the scheduler is concerned).
1628 if (state_ != SENDING_INITIAL_METRICS_LOG) {
1629 scheduler_->UploadFinished(server_is_healthy,
1630 log_manager_.has_unsent_logs());
1631 }
[email protected]d67d1052011-06-09 05:11:411632
1633 // Collect network stats if UMA upload succeeded.
[email protected]b8ddb052012-04-19 02:36:061634 IOThread* io_thread = g_browser_process->io_thread();
1635 if (server_is_healthy && io_thread) {
1636 chrome_browser_net::CollectNetworkStats(network_stats_server_, io_thread);
[email protected]adbb3762012-03-09 22:20:081637 chrome_browser_net::CollectPipeliningCapabilityStatsOnUIThread(
[email protected]b8ddb052012-04-19 02:36:061638 http_pipelining_test_server_, io_thread);
[email protected]aa312812013-04-30 19:46:051639#if defined(OS_WIN)
1640 chrome::CollectTimeTicksStats();
1641#endif
[email protected]adbb3762012-03-09 22:20:081642 }
initial.commit09911bf2008-07-26 23:55:291643}
1644
[email protected]57ecc4b2010-08-11 03:02:511645void MetricsService::IncrementPrefValue(const char* path) {
[email protected]e73c01972008-08-13 00:18:241646 PrefService* pref = g_browser_process->local_state();
1647 DCHECK(pref);
1648 int value = pref->GetInteger(path);
1649 pref->SetInteger(path, value + 1);
1650}
1651
[email protected]57ecc4b2010-08-11 03:02:511652void MetricsService::IncrementLongPrefsValue(const char* path) {
[email protected]0bb1a622009-03-04 03:22:321653 PrefService* pref = g_browser_process->local_state();
1654 DCHECK(pref);
1655 int64 value = pref->GetInt64(path);
[email protected]b42c5e42010-06-03 20:43:251656 pref->SetInt64(path, value + 1);
[email protected]0bb1a622009-03-04 03:22:321657}
1658
[email protected]752a5262013-06-23 14:53:421659void MetricsService::LogLoadStarted(content::WebContents* web_contents) {
[email protected]e6e30ac2014-01-13 21:24:391660 content::RecordAction(base::UserMetricsAction("PageLoad"));
[email protected]dd8d12a2011-09-02 02:10:151661 HISTOGRAM_ENUMERATION("Chrome.UmaPageloadCounter", 1, 2);
[email protected]e73c01972008-08-13 00:18:241662 IncrementPrefValue(prefs::kStabilityPageLoadCount);
[email protected]0bb1a622009-03-04 03:22:321663 IncrementLongPrefsValue(prefs::kUninstallMetricsPageLoadCount);
[email protected]0b33f80b2008-12-17 21:34:361664 // We need to save the prefs, as page load count is a critical stat, and it
1665 // might be lost due to a crash :-(.
initial.commit09911bf2008-07-26 23:55:291666}
1667
[email protected]c3721482012-03-23 16:21:481668void MetricsService::LogRendererCrash(content::RenderProcessHost* host,
1669 base::TerminationStatus status,
[email protected]f1675202012-07-09 15:18:001670 int exit_code) {
[email protected]6f371442011-11-09 06:45:461671 bool was_extension_process =
[email protected]fafdc842014-01-17 18:09:081672 extensions::ProcessMap::Get(host->GetBrowserContext())
1673 ->Contains(host->GetID());
[email protected]c3721482012-03-23 16:21:481674 if (status == base::TERMINATION_STATUS_PROCESS_CRASHED ||
1675 status == base::TERMINATION_STATUS_ABNORMAL_TERMINATION) {
[email protected]d7c1fa62012-06-15 23:35:301676 if (was_extension_process) {
[email protected]718eab62011-10-05 21:16:521677 IncrementPrefValue(prefs::kStabilityExtensionRendererCrashCount);
[email protected]d7c1fa62012-06-15 23:35:301678
[email protected]1026afd2013-03-20 14:28:541679 UMA_HISTOGRAM_SPARSE_SLOWLY("CrashExitCodes.Extension",
1680 MapCrashExitCodeForHistogram(exit_code));
[email protected]d7c1fa62012-06-15 23:35:301681 } else {
[email protected]718eab62011-10-05 21:16:521682 IncrementPrefValue(prefs::kStabilityRendererCrashCount);
initial.commit09911bf2008-07-26 23:55:291683
[email protected]1026afd2013-03-20 14:28:541684 UMA_HISTOGRAM_SPARSE_SLOWLY("CrashExitCodes.Renderer",
1685 MapCrashExitCodeForHistogram(exit_code));
[email protected]d7c1fa62012-06-15 23:35:301686 }
1687
[email protected]718eab62011-10-05 21:16:521688 UMA_HISTOGRAM_PERCENTAGE("BrowserRenderProcessHost.ChildCrashes",
1689 was_extension_process ? 2 : 1);
[email protected]c3721482012-03-23 16:21:481690 } else if (status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED) {
[email protected]718eab62011-10-05 21:16:521691 UMA_HISTOGRAM_PERCENTAGE("BrowserRenderProcessHost.ChildKills",
1692 was_extension_process ? 2 : 1);
[email protected]f1675202012-07-09 15:18:001693 } else if (status == base::TERMINATION_STATUS_STILL_RUNNING) {
1694 UMA_HISTOGRAM_PERCENTAGE("BrowserRenderProcessHost.DisconnectedAlive",
[email protected]718eab62011-10-05 21:16:521695 was_extension_process ? 2 : 1);
[email protected]718eab62011-10-05 21:16:521696 }
[email protected]80a8f312013-12-16 18:00:301697}
[email protected]1f085622009-12-04 05:33:451698
initial.commit09911bf2008-07-26 23:55:291699void MetricsService::LogRendererHang() {
[email protected]e73c01972008-08-13 00:18:241700 IncrementPrefValue(prefs::kStabilityRendererHangCount);
initial.commit09911bf2008-07-26 23:55:291701}
1702
[email protected]c0c55e92011-09-10 18:47:301703bool MetricsService::UmaMetricsProperlyShutdown() {
1704 CHECK(clean_shutdown_status_ == CLEANLY_SHUTDOWN ||
1705 clean_shutdown_status_ == NEED_TO_SHUTDOWN);
1706 return clean_shutdown_status_ == CLEANLY_SHUTDOWN;
1707}
1708
[email protected]60677562013-11-17 15:52:551709void MetricsService::RegisterSyntheticFieldTrial(
1710 const SyntheticTrialGroup& trial) {
1711 for (size_t i = 0; i < synthetic_trial_groups_.size(); ++i) {
1712 if (synthetic_trial_groups_[i].id.name == trial.id.name) {
1713 if (synthetic_trial_groups_[i].id.group != trial.id.group) {
1714 synthetic_trial_groups_[i].id.group = trial.id.group;
[email protected]7a5c07812014-02-26 11:45:411715 synthetic_trial_groups_[i].start_time = base::TimeTicks::Now();
[email protected]60677562013-11-17 15:52:551716 }
1717 return;
1718 }
1719 }
1720
[email protected]7a5c07812014-02-26 11:45:411721 SyntheticTrialGroup trial_group = trial;
1722 trial_group.start_time = base::TimeTicks::Now();
[email protected]60677562013-11-17 15:52:551723 synthetic_trial_groups_.push_back(trial_group);
1724}
1725
[email protected]99c892d2014-03-24 18:11:211726void MetricsService::CheckForClonedInstall() {
[email protected]39076642014-05-05 20:32:551727 state_manager_->CheckForClonedInstall();
[email protected]99c892d2014-03-24 18:11:211728}
1729
[email protected]60677562013-11-17 15:52:551730void MetricsService::GetCurrentSyntheticFieldTrials(
1731 std::vector<chrome_variations::ActiveGroupId>* synthetic_trials) {
1732 DCHECK(synthetic_trials);
1733 synthetic_trials->clear();
1734 const MetricsLog* current_log =
1735 static_cast<const MetricsLog*>(log_manager_.current_log());
1736 for (size_t i = 0; i < synthetic_trial_groups_.size(); ++i) {
1737 if (synthetic_trial_groups_[i].start_time <= current_log->creation_time())
1738 synthetic_trials->push_back(synthetic_trial_groups_[i].id);
1739 }
1740}
1741
[email protected]466f3c12011-03-23 21:20:381742void MetricsService::LogCleanShutdown() {
[email protected]acd55b32011-09-05 17:35:311743 // Redundant hack to write pref ASAP.
[email protected]84c384e2013-03-01 23:20:191744 MarkAppCleanShutdownAndCommit();
1745
[email protected]c0c55e92011-09-10 18:47:301746 // Redundant setting to assure that we always reset this value at shutdown
1747 // (and that we don't use some alternate path, and not call LogCleanShutdown).
1748 clean_shutdown_status_ = CLEANLY_SHUTDOWN;
[email protected]acd55b32011-09-05 17:35:311749
[email protected]466f3c12011-03-23 21:20:381750 RecordBooleanPrefValue(prefs::kStabilityExitedCleanly, true);
[email protected]6a6d0d12013-10-28 15:58:191751 PrefService* pref = g_browser_process->local_state();
1752 pref->SetInteger(prefs::kStabilityExecutionPhase,
[email protected]6d67ea0d2013-11-14 11:02:211753 MetricsService::SHUTDOWN_COMPLETE);
[email protected]466f3c12011-03-23 21:20:381754}
1755
[email protected]c1834a92011-01-21 18:21:031756#if defined(OS_CHROMEOS)
1757void MetricsService::LogChromeOSCrash(const std::string &crash_type) {
1758 if (crash_type == "user")
1759 IncrementPrefValue(prefs::kStabilityOtherUserCrashCount);
1760 else if (crash_type == "kernel")
1761 IncrementPrefValue(prefs::kStabilityKernelCrashCount);
1762 else if (crash_type == "uncleanshutdown")
1763 IncrementPrefValue(prefs::kStabilitySystemUncleanShutdownCount);
1764 else
1765 NOTREACHED() << "Unexpected Chrome OS crash type " << crash_type;
1766 // Wake up metrics logs sending if necessary now that new
1767 // log data is available.
1768 HandleIdleSinceLastTransmission(false);
1769}
1770#endif // OS_CHROMEOS
1771
[email protected]650b2d52013-02-10 03:41:451772void MetricsService::LogPluginLoadingError(const base::FilePath& plugin_path) {
[email protected]d7bd3e52013-07-21 04:29:201773 content::WebPluginInfo plugin;
[email protected]cd937072012-07-02 09:00:291774 bool success =
1775 content::PluginService::GetInstance()->GetPluginInfoByPath(plugin_path,
1776 &plugin);
1777 DCHECK(success);
1778 ChildProcessStats& stats = child_process_stats_buffer_[plugin.name];
1779 // Initialize the type if this entry is new.
1780 if (stats.process_type == content::PROCESS_TYPE_UNKNOWN) {
1781 // The plug-in process might not actually of type PLUGIN (which means
1782 // NPAPI), but we only care that it is *a* plug-in process.
1783 stats.process_type = content::PROCESS_TYPE_PLUGIN;
1784 } else {
1785 DCHECK(IsPluginProcess(stats.process_type));
1786 }
1787 stats.loading_errors++;
1788}
1789
[email protected]f4eaf7b92013-02-28 22:00:401790MetricsService::ChildProcessStats& MetricsService::GetChildProcessStats(
1791 const content::ChildProcessData& data) {
[email protected]439f1e32013-12-09 20:09:091792 const base::string16& child_name = data.name;
[email protected]f3b357692013-03-22 05:16:131793 if (!ContainsKey(child_process_stats_buffer_, child_name)) {
1794 child_process_stats_buffer_[child_name] =
1795 ChildProcessStats(data.process_type);
1796 }
[email protected]f4eaf7b92013-02-28 22:00:401797 return child_process_stats_buffer_[child_name];
initial.commit09911bf2008-07-26 23:55:291798}
1799
initial.commit09911bf2008-07-26 23:55:291800void MetricsService::RecordPluginChanges(PrefService* pref) {
[email protected]f8628c22011-04-05 12:10:181801 ListPrefUpdate update(pref, prefs::kStabilityPluginStats);
[email protected]cb1078de2013-12-23 20:04:221802 base::ListValue* plugins = update.Get();
initial.commit09911bf2008-07-26 23:55:291803 DCHECK(plugins);
1804
[email protected]cb1078de2013-12-23 20:04:221805 for (base::ListValue::iterator value_iter = plugins->begin();
initial.commit09911bf2008-07-26 23:55:291806 value_iter != plugins->end(); ++value_iter) {
[email protected]cb1078de2013-12-23 20:04:221807 if (!(*value_iter)->IsType(base::Value::TYPE_DICTIONARY)) {
[email protected]a063c102010-07-22 22:20:191808 NOTREACHED();
initial.commit09911bf2008-07-26 23:55:291809 continue;
1810 }
1811
[email protected]cb1078de2013-12-23 20:04:221812 base::DictionaryValue* plugin_dict =
1813 static_cast<base::DictionaryValue*>(*value_iter);
[email protected]57ecc4b2010-08-11 03:02:511814 std::string plugin_name;
[email protected]8e50b602009-03-03 22:59:431815 plugin_dict->GetString(prefs::kStabilityPluginName, &plugin_name);
[email protected]6470ee8f2009-03-03 20:46:401816 if (plugin_name.empty()) {
[email protected]a063c102010-07-22 22:20:191817 NOTREACHED();
initial.commit09911bf2008-07-26 23:55:291818 continue;
1819 }
1820
[email protected]57ecc4b2010-08-11 03:02:511821 // TODO(viettrungluu): remove conversions
[email protected]6778fed2013-12-24 20:09:371822 base::string16 name16 = base::UTF8ToUTF16(plugin_name);
[email protected]68b9e72b2011-08-05 23:08:221823 if (child_process_stats_buffer_.find(name16) ==
1824 child_process_stats_buffer_.end()) {
initial.commit09911bf2008-07-26 23:55:291825 continue;
[email protected]68b9e72b2011-08-05 23:08:221826 }
initial.commit09911bf2008-07-26 23:55:291827
[email protected]68b9e72b2011-08-05 23:08:221828 ChildProcessStats stats = child_process_stats_buffer_[name16];
initial.commit09911bf2008-07-26 23:55:291829 if (stats.process_launches) {
1830 int launches = 0;
[email protected]8e50b602009-03-03 22:59:431831 plugin_dict->GetInteger(prefs::kStabilityPluginLaunches, &launches);
initial.commit09911bf2008-07-26 23:55:291832 launches += stats.process_launches;
[email protected]8e50b602009-03-03 22:59:431833 plugin_dict->SetInteger(prefs::kStabilityPluginLaunches, launches);
initial.commit09911bf2008-07-26 23:55:291834 }
1835 if (stats.process_crashes) {
1836 int crashes = 0;
[email protected]8e50b602009-03-03 22:59:431837 plugin_dict->GetInteger(prefs::kStabilityPluginCrashes, &crashes);
initial.commit09911bf2008-07-26 23:55:291838 crashes += stats.process_crashes;
[email protected]8e50b602009-03-03 22:59:431839 plugin_dict->SetInteger(prefs::kStabilityPluginCrashes, crashes);
initial.commit09911bf2008-07-26 23:55:291840 }
1841 if (stats.instances) {
1842 int instances = 0;
[email protected]8e50b602009-03-03 22:59:431843 plugin_dict->GetInteger(prefs::kStabilityPluginInstances, &instances);
initial.commit09911bf2008-07-26 23:55:291844 instances += stats.instances;
[email protected]8e50b602009-03-03 22:59:431845 plugin_dict->SetInteger(prefs::kStabilityPluginInstances, instances);
initial.commit09911bf2008-07-26 23:55:291846 }
[email protected]cd937072012-07-02 09:00:291847 if (stats.loading_errors) {
1848 int loading_errors = 0;
1849 plugin_dict->GetInteger(prefs::kStabilityPluginLoadingErrors,
1850 &loading_errors);
1851 loading_errors += stats.loading_errors;
1852 plugin_dict->SetInteger(prefs::kStabilityPluginLoadingErrors,
1853 loading_errors);
1854 }
initial.commit09911bf2008-07-26 23:55:291855
[email protected]68b9e72b2011-08-05 23:08:221856 child_process_stats_buffer_.erase(name16);
initial.commit09911bf2008-07-26 23:55:291857 }
1858
1859 // Now go through and add dictionaries for plugins that didn't already have
1860 // reports in Local State.
[email protected]d2065e062013-12-12 23:49:521861 for (std::map<base::string16, ChildProcessStats>::iterator cache_iter =
[email protected]a27a9382009-02-11 23:55:101862 child_process_stats_buffer_.begin();
1863 cache_iter != child_process_stats_buffer_.end(); ++cache_iter) {
[email protected]a27a9382009-02-11 23:55:101864 ChildProcessStats stats = cache_iter->second;
[email protected]0d84c5d2009-10-09 01:10:421865
1866 // Insert only plugins information into the plugins list.
[email protected]8d5f1dae2011-11-11 14:30:411867 if (!IsPluginProcess(stats.process_type))
[email protected]0d84c5d2009-10-09 01:10:421868 continue;
1869
[email protected]57ecc4b2010-08-11 03:02:511870 // TODO(viettrungluu): remove conversion
[email protected]6778fed2013-12-24 20:09:371871 std::string plugin_name = base::UTF16ToUTF8(cache_iter->first);
[email protected]0d84c5d2009-10-09 01:10:421872
[email protected]cb1078de2013-12-23 20:04:221873 base::DictionaryValue* plugin_dict = new base::DictionaryValue;
initial.commit09911bf2008-07-26 23:55:291874
[email protected]8e50b602009-03-03 22:59:431875 plugin_dict->SetString(prefs::kStabilityPluginName, plugin_name);
1876 plugin_dict->SetInteger(prefs::kStabilityPluginLaunches,
initial.commit09911bf2008-07-26 23:55:291877 stats.process_launches);
[email protected]8e50b602009-03-03 22:59:431878 plugin_dict->SetInteger(prefs::kStabilityPluginCrashes,
initial.commit09911bf2008-07-26 23:55:291879 stats.process_crashes);
[email protected]8e50b602009-03-03 22:59:431880 plugin_dict->SetInteger(prefs::kStabilityPluginInstances,
initial.commit09911bf2008-07-26 23:55:291881 stats.instances);
[email protected]cd937072012-07-02 09:00:291882 plugin_dict->SetInteger(prefs::kStabilityPluginLoadingErrors,
1883 stats.loading_errors);
initial.commit09911bf2008-07-26 23:55:291884 plugins->Append(plugin_dict);
1885 }
[email protected]a27a9382009-02-11 23:55:101886 child_process_stats_buffer_.clear();
initial.commit09911bf2008-07-26 23:55:291887}
1888
[email protected]e5ad60a2014-03-11 03:54:041889bool MetricsService::ShouldLogEvents() {
1890 // We simply don't log events to UMA if there is a single incognito
initial.commit09911bf2008-07-26 23:55:291891 // session visible. The problem is that we always notify using the orginal
1892 // profile in order to simplify notification processing.
[email protected]e764e582012-08-01 03:01:291893 return !chrome::IsOffTheRecordSessionActive();
initial.commit09911bf2008-07-26 23:55:291894}
1895
[email protected]57ecc4b2010-08-11 03:02:511896void MetricsService::RecordBooleanPrefValue(const char* path, bool value) {
initial.commit09911bf2008-07-26 23:55:291897 DCHECK(IsSingleThreaded());
1898
1899 PrefService* pref = g_browser_process->local_state();
1900 DCHECK(pref);
1901
1902 pref->SetBoolean(path, value);
1903 RecordCurrentState(pref);
1904}
1905
1906void MetricsService::RecordCurrentState(PrefService* pref) {
[email protected]0bb1a622009-03-04 03:22:321907 pref->SetInt64(prefs::kStabilityLastTimestampSec, Time::Now().ToTimeT());
initial.commit09911bf2008-07-26 23:55:291908
1909 RecordPluginChanges(pref);
1910}
1911
[email protected]8d5f1dae2011-11-11 14:30:411912// static
[email protected]f3b357692013-03-22 05:16:131913bool MetricsService::IsPluginProcess(int process_type) {
1914 return (process_type == content::PROCESS_TYPE_PLUGIN ||
1915 process_type == content::PROCESS_TYPE_PPAPI_PLUGIN ||
1916 process_type == content::PROCESS_TYPE_PPAPI_BROKER);
[email protected]8d5f1dae2011-11-11 14:30:411917}
1918
[email protected]5ccaa412009-11-13 22:00:161919#if defined(OS_CHROMEOS)
[email protected]29cf16772010-04-21 15:13:471920void MetricsService::StartExternalMetrics() {
[email protected]5ccaa412009-11-13 22:00:161921 external_metrics_ = new chromeos::ExternalMetrics;
[email protected]29cf16772010-04-21 15:13:471922 external_metrics_->Start();
[email protected]5ccaa412009-11-13 22:00:161923}
1924#endif
[email protected]3819f2ee2011-08-21 09:44:381925
1926// static
1927bool MetricsServiceHelper::IsMetricsReportingEnabled() {
1928 bool result = false;
1929 const PrefService* local_state = g_browser_process->local_state();
1930 if (local_state) {
1931 const PrefService::Preference* uma_pref =
1932 local_state->FindPreference(prefs::kMetricsReportingEnabled);
1933 if (uma_pref) {
1934 bool success = uma_pref->GetValue()->GetAsBoolean(&result);
1935 DCHECK(success);
1936 }
1937 }
1938 return result;
1939}
[email protected]1ef13cf2014-03-21 22:44:011940
1941bool MetricsServiceHelper::IsCrashReportingEnabled() {
1942#if defined(GOOGLE_CHROME_BUILD)
1943#if defined(OS_CHROMEOS)
1944 bool reporting_enabled = false;
1945 chromeos::CrosSettings::Get()->GetBoolean(chromeos::kStatsReportingPref,
1946 &reporting_enabled);
1947 return reporting_enabled;
1948#elif defined(OS_ANDROID)
1949 // Android has its own settings for metrics / crash uploading.
1950 const PrefService* prefs = g_browser_process->local_state();
1951 return prefs->GetBoolean(prefs::kCrashReportingEnabled);
1952#else
1953 return MetricsServiceHelper::IsMetricsReportingEnabled();
1954#endif
1955#else
1956 return false;
1957#endif
1958}
[email protected]2a321de32014-05-10 19:59:061959
1960void MetricsServiceHelper::AddMetricsServiceObserver(
1961 MetricsServiceObserver* observer) {
1962 MetricsService* metrics_service = g_browser_process->metrics_service();
1963 if (metrics_service)
1964 metrics_service->AddObserver(observer);
1965}
1966
1967void MetricsServiceHelper::RemoveMetricsServiceObserver(
1968 MetricsServiceObserver* observer) {
1969 MetricsService* metrics_service = g_browser_process->metrics_service();
1970 if (metrics_service)
1971 metrics_service->RemoveObserver(observer);
1972}