blob: 55164d1f2c013d91edb20b6b4f97f65d78d664cf [file] [log] [blame]
[email protected]d6147bd2014-06-11 01:58:191// Copyright 2014 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//
Steven Holte2c294a32015-03-12 21:45:0379// 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_LOGS, // Sending logs and creating new ones when we run out.
initial.commit09911bf2008-07-26 23:55:2983//
84// In more detail, we have:
85//
86// INITIALIZED, // Constructor was called.
87// The MS has been constructed, but has taken no actions to compose the
88// initial log.
89//
[email protected]80a8f312013-12-16 18:00:3090// INIT_TASK_SCHEDULED, // Waiting for deferred init tasks to finish.
initial.commit09911bf2008-07-26 23:55:2991// Typically about 30 seconds after startup, a task is sent to a second thread
[email protected]85ed9d42010-06-08 22:37:4492// (the file thread) to perform deferred (lower priority and slower)
93// initialization steps such as getting the list of plugins. That task will
94// (when complete) make an async callback (via a Task) to indicate the
95// completion.
initial.commit09911bf2008-07-26 23:55:2996//
[email protected]85ed9d42010-06-08 22:37:4497// INIT_TASK_DONE, // Waiting for timer to send initial log.
initial.commit09911bf2008-07-26 23:55:2998// The callback has arrived, and it is now possible for an initial log to be
99// created. This callback typically arrives back less than one second after
[email protected]85ed9d42010-06-08 22:37:44100// the deferred init task is dispatched.
initial.commit09911bf2008-07-26 23:55:29101//
Steven Holte2c294a32015-03-12 21:45:03102// SENDING_LOGS, // Sending logs an creating new ones when we run out.
103// Logs from previous sessions have been loaded, and initial logs have been
104// created (an optional stability log and the first metrics log). We will
105// send all of these logs, and when run out, we will start cutting new logs
106// to send. We will also cut a new log if we expect a shutdown.
[email protected]80a8f312013-12-16 18:00:30107//
Steven Holte2c294a32015-03-12 21:45:03108// The progression through the above states is simple, and sequential.
109// States proceed from INITIAL to SENDING_LOGS, and remain in the latter until
110// shutdown.
initial.commit09911bf2008-07-26 23:55:29111//
Steven Holte2c294a32015-03-12 21:45:03112// Also note that whenever we successfully send a log, we mirror the list
[email protected]cac267c2011-09-29 15:18:10113// of logs into the PrefService. This ensures that IF we crash, we won't start
114// up and retransmit our old logs again.
initial.commit09911bf2008-07-26 23:55:29115//
116// Due to race conditions, it is always possible that a log file could be sent
117// twice. For example, if a log file is sent, but not yet acknowledged by
118// the external server, and the user shuts down, then a copy of the log may be
119// saved for re-transmission. These duplicates could be filtered out server
[email protected]281d2882009-01-20 20:32:42120// side, but are not expected to be a significant problem.
initial.commit09911bf2008-07-26 23:55:29121//
122//
123//------------------------------------------------------------------------------
124
[email protected]d6147bd2014-06-11 01:58:19125#include "components/metrics/metrics_service.h"
[email protected]40bcc302009-03-02 20:50:39126
avi26062922015-12-26 00:14:18127#include <stddef.h>
dchengd99c42a2016-04-21 21:54:13128
dcheng51606352015-12-26 21:16:23129#include <algorithm>
130#include <utility>
avi26062922015-12-26 00:14:18131
[email protected]7f7f1962011-04-20 15:58:16132#include "base/bind.h"
133#include "base/callback.h"
holte68395852017-01-10 20:40:21134#include "base/feature_list.h"
skyostilb0daa012015-06-02 19:03:48135#include "base/location.h"
dchengd99c42a2016-04-21 21:54:13136#include "base/memory/ptr_util.h"
[email protected]acc2ce5512014-05-22 18:29:13137#include "base/metrics/histogram_base.h"
asvitkine454600f2015-06-16 16:34:50138#include "base/metrics/histogram_macros.h"
[email protected]acc2ce5512014-05-22 18:29:13139#include "base/metrics/histogram_samples.h"
bcwhite33d95806a2016-03-16 02:37:45140#include "base/metrics/persistent_histogram_allocator.h"
[email protected]1026afd2013-03-20 14:28:54141#include "base/metrics/sparse_histogram.h"
[email protected]567d30e2012-07-13 21:48:29142#include "base/metrics/statistics_recorder.h"
skyostilb0daa012015-06-02 19:03:48143#include "base/single_thread_task_runner.h"
[email protected]3ea1b182013-02-08 22:38:41144#include "base/strings/string_number_conversions.h"
[email protected]112158af2013-06-07 23:46:18145#include "base/strings/utf_string_conversions.h"
gab7966d312016-05-11 20:35:01146#include "base/threading/thread_task_runner_handle.h"
[email protected]64b8652c2014-07-16 19:14:28147#include "base/time/time.h"
[email protected]ed0fd002012-04-25 23:10:34148#include "base/tracked_objects.h"
avi26062922015-12-26 00:14:18149#include "build/build_config.h"
gayane0b46091c2016-04-07 21:01:05150#include "components/metrics/data_use_tracker.h"
[email protected]91b1d912014-06-05 10:52:08151#include "components/metrics/metrics_log.h"
[email protected]064107e2014-05-02 00:59:06152#include "components/metrics/metrics_log_manager.h"
[email protected]0d5a61a82014-05-31 22:28:34153#include "components/metrics/metrics_log_uploader.h"
[email protected]7f07db62014-05-15 01:12:45154#include "components/metrics/metrics_pref_names.h"
[email protected]14bb46692014-05-20 17:16:45155#include "components/metrics/metrics_reporting_scheduler.h"
holte68395852017-01-10 20:40:21156#include "components/metrics/metrics_rotation_scheduler.h"
[email protected]73929422014-05-22 08:19:05157#include "components/metrics/metrics_service_client.h"
[email protected]16a30912014-06-04 00:20:04158#include "components/metrics/metrics_state_manager.h"
holte68395852017-01-10 20:40:21159#include "components/metrics/metrics_upload_scheduler.h"
holte567a16f22017-01-06 01:53:45160#include "components/metrics/url_constants.h"
brettwf00b9b42016-02-01 22:11:38161#include "components/prefs/pref_registry_simple.h"
162#include "components/prefs/pref_service.h"
[email protected]50ae9f12013-08-29 18:03:22163#include "components/variations/entropy_provider.h"
initial.commit09911bf2008-07-26 23:55:29164
asvitkinecbd420732014-08-26 22:15:40165namespace metrics {
[email protected]e1acf6f2008-10-27 20:43:33166
[email protected]fe58acc22012-02-29 01:29:58167namespace {
[email protected]b2a4812d2012-02-28 05:31:31168
holte68395852017-01-10 20:40:21169// This feature moves the upload schedule to a seperate schedule from the
170// log rotation schedule. This may change upload timing slightly, but
171// would allow some compartmentalization of uploader logic to allow more
172// code reuse between different metrics services.
173const base::Feature kUploadSchedulerFeature{"UMAUploadScheduler",
174 base::FEATURE_DISABLED_BY_DEFAULT};
175
rkaplow02e248432017-01-20 23:39:41176// This drops records if the number of events (user action and omnibox) exceeds
177// the kEventLimit.
178const base::Feature kUMAThrottleEvents{"UMAThrottleEvents",
179 base::FEATURE_ENABLED_BY_DEFAULT};
180
holte68395852017-01-10 20:40:21181bool HasUploadScheduler() {
182 return base::FeatureList::IsEnabled(kUploadSchedulerFeature);
183}
184
[email protected]7f7f1962011-04-20 15:58:16185// The delay, in seconds, after starting recording before doing expensive
186// initialization work.
[email protected]12180f82012-10-10 21:13:30187#if defined(OS_ANDROID) || defined(OS_IOS)
188// On mobile devices, a significant portion of sessions last less than a minute.
189// Use a shorter timer on these platforms to avoid losing data.
190// TODO(dfalcantara): To avoid delaying startup, tighten up initialization so
191// that it occurs after the user gets their initial page.
192const int kInitializationDelaySeconds = 5;
193#else
[email protected]fe58acc22012-02-29 01:29:58194const int kInitializationDelaySeconds = 30;
[email protected]12180f82012-10-10 21:13:30195#endif
[email protected]252873ef2008-08-04 21:59:45196
[email protected]54702c92011-04-15 15:06:43197// The maximum number of events in a log uploaded to the UMA server.
[email protected]fe58acc22012-02-29 01:29:58198const int kEventLimit = 2400;
[email protected]68475e602008-08-22 03:21:15199
200// If an upload fails, and the transmission was over this byte count, then we
201// will discard the log, and not try to retransmit it. We also don't persist
202// the log to the prefs for transmission during the next chrome session if this
203// limit is exceeded.
[email protected]a63006e2014-06-20 05:22:32204const size_t kUploadLogAvoidRetransmitSize = 100 * 1024;
initial.commit09911bf2008-07-26 23:55:29205
[email protected]4266def22012-05-17 01:02:40206enum ResponseStatus {
207 UNKNOWN_FAILURE,
208 SUCCESS,
209 BAD_REQUEST, // Invalid syntax or log too large.
[email protected]9f5c1ce82012-05-23 23:11:28210 NO_RESPONSE,
[email protected]4266def22012-05-17 01:02:40211 NUM_RESPONSE_STATUSES
212};
213
214ResponseStatus ResponseCodeToStatus(int response_code) {
215 switch (response_code) {
[email protected]0d5a61a82014-05-31 22:28:34216 case -1:
217 return NO_RESPONSE;
[email protected]4266def22012-05-17 01:02:40218 case 200:
219 return SUCCESS;
220 case 400:
221 return BAD_REQUEST;
222 default:
223 return UNKNOWN_FAILURE;
224 }
225}
226
hashimotoa5c00e28d2015-03-27 06:28:37227#if defined(OS_ANDROID) || defined(OS_IOS)
erikwright65b58df2014-09-12 00:05:28228void MarkAppCleanShutdownAndCommit(CleanExitBeacon* clean_exit_beacon,
229 PrefService* local_state) {
230 clean_exit_beacon->WriteBeaconValue(true);
holtea27eadf2017-01-26 01:58:59231 ExecutionPhaseManager(local_state).OnAppEnterBackground();
[email protected]84c384e2013-03-01 23:20:19232 // Start writing right away (write happens on a different thread).
[email protected]24f81ca2014-05-26 15:59:34233 local_state->CommitPendingWrite();
[email protected]84c384e2013-03-01 23:20:19234}
hashimotoa5c00e28d2015-03-27 06:28:37235#endif // defined(OS_ANDROID) || defined(OS_IOS)
[email protected]84c384e2013-03-01 23:20:19236
[email protected]20f999b52012-08-24 22:32:59237} // namespace
initial.commit09911bf2008-07-26 23:55:29238
[email protected]c0c55e92011-09-10 18:47:30239// static
240MetricsService::ShutdownCleanliness MetricsService::clean_shutdown_status_ =
241 MetricsService::CLEANLY_SHUTDOWN;
242
initial.commit09911bf2008-07-26 23:55:29243// static
[email protected]b1de2c72013-02-06 02:45:47244void MetricsService::RegisterPrefs(PrefRegistrySimple* registry) {
asvitkinea63d19e2014-10-24 16:19:39245 MetricsStateManager::RegisterPrefs(registry);
[email protected]91b1d912014-06-05 10:52:08246 MetricsLog::RegisterPrefs(registry);
gayane0b46091c2016-04-07 21:01:05247 DataUseTracker::RegisterPrefs(registry);
[email protected]39076642014-05-05 20:32:55248
asvitkinea63d19e2014-10-24 16:19:39249 registry->RegisterInt64Pref(prefs::kInstallDate, 0);
[email protected]65801452014-07-09 05:42:41250
asvitkinea63d19e2014-10-24 16:19:39251 registry->RegisterInt64Pref(prefs::kStabilityLaunchTimeSec, 0);
252 registry->RegisterInt64Pref(prefs::kStabilityLastTimestampSec, 0);
253 registry->RegisterStringPref(prefs::kStabilityStatsVersion, std::string());
254 registry->RegisterInt64Pref(prefs::kStabilityStatsBuildTime, 0);
255 registry->RegisterBooleanPref(prefs::kStabilityExitedCleanly, true);
holtea27eadf2017-01-26 01:58:59256 ExecutionPhaseManager::RegisterPrefs(registry);
asvitkinea63d19e2014-10-24 16:19:39257 registry->RegisterBooleanPref(prefs::kStabilitySessionEndCompleted, true);
258 registry->RegisterIntegerPref(prefs::kMetricsSessionID, -1);
[email protected]0f2f7792013-11-28 16:09:14259
asvitkinea63d19e2014-10-24 16:19:39260 registry->RegisterListPref(prefs::kMetricsInitialLogs);
261 registry->RegisterListPref(prefs::kMetricsOngoingLogs);
[email protected]0bb1a622009-03-04 03:22:32262
asvitkinea63d19e2014-10-24 16:19:39263 registry->RegisterInt64Pref(prefs::kUninstallLaunchCount, 0);
264 registry->RegisterInt64Pref(prefs::kUninstallMetricsUptimeSec, 0);
initial.commit09911bf2008-07-26 23:55:29265}
266
asvitkinea63d19e2014-10-24 16:19:39267MetricsService::MetricsService(MetricsStateManager* state_manager,
268 MetricsServiceClient* client,
[email protected]24f81ca2014-05-26 15:59:34269 PrefService* local_state)
270 : log_manager_(local_state, kUploadLogAvoidRetransmitSize),
[email protected]acc2ce5512014-05-22 18:29:13271 histogram_snapshot_manager_(this),
[email protected]7f07db62014-05-15 01:12:45272 state_manager_(state_manager),
[email protected]728de072014-05-21 09:20:32273 client_(client),
[email protected]24f81ca2014-05-26 15:59:34274 local_state_(local_state),
erikwright65b58df2014-09-12 00:05:28275 clean_exit_beacon_(client->GetRegistryBackupKey(), local_state),
wittman622851e2015-07-31 18:13:40276 recording_state_(UNSET),
[email protected]d01b8732008-10-16 02:18:07277 reporting_active_(false),
[email protected]410938e02012-10-24 16:33:59278 test_mode_active_(false),
[email protected]d01b8732008-10-16 02:18:07279 state_(INITIALIZED),
[email protected]0d5a61a82014-05-31 22:28:34280 log_upload_in_progress_(false),
[email protected]d01b8732008-10-16 02:18:07281 idle_since_last_transmission_(false),
[email protected]80a8f312013-12-16 18:00:30282 session_id_(-1),
gayane0b46091c2016-04-07 21:01:05283 data_use_tracker_(DataUseTracker::Create(local_state_)),
holte57fcaed2017-01-23 22:14:31284 self_ptr_factory_(this) {
holtea07de2062017-01-21 03:43:15285 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]39076642014-05-05 20:32:55286 DCHECK(state_manager_);
[email protected]728de072014-05-21 09:20:32287 DCHECK(client_);
[email protected]24f81ca2014-05-26 15:59:34288 DCHECK(local_state_);
[email protected]64b8652c2014-07-16 19:14:28289
290 // Set the install date if this is our first run.
avi26062922015-12-26 00:14:18291 int64_t install_date = local_state_->GetInt64(prefs::kInstallDate);
asvitkinea63d19e2014-10-24 16:19:39292 if (install_date == 0)
293 local_state_->SetInt64(prefs::kInstallDate, base::Time::Now().ToTimeT());
initial.commit09911bf2008-07-26 23:55:29294}
295
296MetricsService::~MetricsService() {
[email protected]410938e02012-10-24 16:33:59297 DisableRecording();
initial.commit09911bf2008-07-26 23:55:29298}
299
[email protected]39076642014-05-05 20:32:55300void MetricsService::InitializeMetricsRecordingState() {
301 InitializeMetricsState();
[email protected]80a8f312013-12-16 18:00:30302
gayaned52ca402015-02-23 21:23:06303 base::Closure upload_callback =
304 base::Bind(&MetricsService::StartScheduledUpload,
305 self_ptr_factory_.GetWeakPtr());
holte68395852017-01-10 20:40:21306
307 if (HasUploadScheduler()) {
308 rotation_scheduler_.reset(new MetricsRotationScheduler(
309 upload_callback,
310 // MetricsServiceClient outlives MetricsService, and
311 // MetricsRotationScheduler is tied to the lifetime of |this|.
312 base::Bind(&MetricsServiceClient::GetStandardUploadInterval,
313 base::Unretained(client_))));
314 base::Closure send_next_log_callback = base::Bind(
315 &MetricsService::SendNextLog, self_ptr_factory_.GetWeakPtr());
316 upload_scheduler_.reset(new MetricsUploadScheduler(send_next_log_callback));
317 } else {
318 scheduler_.reset(new MetricsReportingScheduler(
319 upload_callback,
320 // MetricsServiceClient outlives MetricsService, and
321 // MetricsReportingScheduler is tied to the lifetime of |this|.
322 base::Bind(&MetricsServiceClient::GetStandardUploadInterval,
323 base::Unretained(client_))));
324 }
dhsharpb0073a22016-02-18 21:54:09325
bcwhite34c6bbf2016-02-19 22:14:46326 for (MetricsProvider* provider : metrics_providers_)
327 provider->Init();
[email protected]80a8f312013-12-16 18:00:30328}
329
[email protected]d01b8732008-10-16 02:18:07330void MetricsService::Start() {
[email protected]b1c8dc02011-04-13 18:32:04331 HandleIdleSinceLastTransmission(false);
[email protected]410938e02012-10-24 16:33:59332 EnableRecording();
333 EnableReporting();
[email protected]d01b8732008-10-16 02:18:07334}
335
[email protected]410938e02012-10-24 16:33:59336void MetricsService::StartRecordingForTests() {
337 test_mode_active_ = true;
338 EnableRecording();
339 DisableReporting();
[email protected]d01b8732008-10-16 02:18:07340}
341
342void MetricsService::Stop() {
[email protected]b1c8dc02011-04-13 18:32:04343 HandleIdleSinceLastTransmission(false);
[email protected]410938e02012-10-24 16:33:59344 DisableReporting();
345 DisableRecording();
346}
347
348void MetricsService::EnableReporting() {
349 if (reporting_active_)
350 return;
351 reporting_active_ = true;
352 StartSchedulerIfNecessary();
353}
354
355void MetricsService::DisableReporting() {
356 reporting_active_ = false;
[email protected]d01b8732008-10-16 02:18:07357}
358
[email protected]edafd4c2011-05-10 17:18:53359std::string MetricsService::GetClientId() {
[email protected]39076642014-05-05 20:32:55360 return state_manager_->client_id();
[email protected]edafd4c2011-05-10 17:18:53361}
362
avi26062922015-12-26 00:14:18363int64_t MetricsService::GetInstallDate() {
asvitkinea63d19e2014-10-24 16:19:39364 return local_state_->GetInt64(prefs::kInstallDate);
[email protected]65801452014-07-09 05:42:41365}
366
avi26062922015-12-26 00:14:18367int64_t MetricsService::GetMetricsReportingEnabledDate() {
olivierrobinc3dfc5b2015-04-07 19:12:00368 return local_state_->GetInt64(prefs::kMetricsReportingEnabledTimestamp);
369}
370
drogerb8d286e42015-07-08 09:07:09371bool MetricsService::WasLastShutdownClean() const {
372 return clean_exit_beacon_.exited_cleanly();
373}
374
[email protected]410938e02012-10-24 16:33:59375void MetricsService::EnableRecording() {
holtea07de2062017-01-21 03:43:15376 DCHECK(thread_checker_.CalledOnValidThread());
initial.commit09911bf2008-07-26 23:55:29377
wittman622851e2015-07-31 18:13:40378 if (recording_state_ == ACTIVE)
initial.commit09911bf2008-07-26 23:55:29379 return;
wittman622851e2015-07-31 18:13:40380 recording_state_ = ACTIVE;
initial.commit09911bf2008-07-26 23:55:29381
[email protected]39076642014-05-05 20:32:55382 state_manager_->ForceClientIdCreation();
[email protected]9d1b0152014-07-09 18:53:22383 client_->SetMetricsClientId(state_manager_->client_id());
[email protected]410938e02012-10-24 16:33:59384 if (!log_manager_.current_log())
385 OpenNewLog();
[email protected]005ef3e2009-05-22 20:55:46386
bcwhite34c6bbf2016-02-19 22:14:46387 for (MetricsProvider* provider : metrics_providers_)
388 provider->OnRecordingEnabled();
[email protected]85791b0b2014-05-20 15:18:58389
[email protected]e6e30ac2014-01-13 21:24:39390 base::RemoveActionCallback(action_callback_);
[email protected]dd98f392013-02-04 13:03:22391 action_callback_ = base::Bind(&MetricsService::OnUserAction,
392 base::Unretained(this));
[email protected]e6e30ac2014-01-13 21:24:39393 base::AddActionCallback(action_callback_);
[email protected]410938e02012-10-24 16:33:59394}
395
396void MetricsService::DisableRecording() {
holtea07de2062017-01-21 03:43:15397 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]410938e02012-10-24 16:33:59398
wittman622851e2015-07-31 18:13:40399 if (recording_state_ == INACTIVE)
[email protected]410938e02012-10-24 16:33:59400 return;
wittman622851e2015-07-31 18:13:40401 recording_state_ = INACTIVE;
[email protected]410938e02012-10-24 16:33:59402
[email protected]e6e30ac2014-01-13 21:24:39403 base::RemoveActionCallback(action_callback_);
[email protected]85791b0b2014-05-20 15:18:58404
bcwhite34c6bbf2016-02-19 22:14:46405 for (MetricsProvider* provider : metrics_providers_)
406 provider->OnRecordingDisabled();
[email protected]85791b0b2014-05-20 15:18:58407
[email protected]410938e02012-10-24 16:33:59408 PushPendingLogsToPersistentStorage();
initial.commit09911bf2008-07-26 23:55:29409}
410
[email protected]d01b8732008-10-16 02:18:07411bool MetricsService::recording_active() const {
holtea07de2062017-01-21 03:43:15412 DCHECK(thread_checker_.CalledOnValidThread());
wittman622851e2015-07-31 18:13:40413 return recording_state_ == ACTIVE;
initial.commit09911bf2008-07-26 23:55:29414}
415
[email protected]d01b8732008-10-16 02:18:07416bool MetricsService::reporting_active() const {
holtea07de2062017-01-21 03:43:15417 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]d01b8732008-10-16 02:18:07418 return reporting_active_;
initial.commit09911bf2008-07-26 23:55:29419}
420
[email protected]acc2ce5512014-05-22 18:29:13421void MetricsService::RecordDelta(const base::HistogramBase& histogram,
422 const base::HistogramSamples& snapshot) {
423 log_manager_.current_log()->RecordHistogramDelta(histogram.histogram_name(),
424 snapshot);
425}
426
427void MetricsService::InconsistencyDetected(
428 base::HistogramBase::Inconsistency problem) {
429 UMA_HISTOGRAM_ENUMERATION("Histogram.InconsistenciesBrowser",
430 problem, base::HistogramBase::NEVER_EXCEEDED_VALUE);
431}
432
433void MetricsService::UniqueInconsistencyDetected(
434 base::HistogramBase::Inconsistency problem) {
435 UMA_HISTOGRAM_ENUMERATION("Histogram.InconsistenciesBrowserUnique",
436 problem, base::HistogramBase::NEVER_EXCEEDED_VALUE);
437}
438
439void MetricsService::InconsistencyDetectedInLoggedCount(int amount) {
440 UMA_HISTOGRAM_COUNTS("Histogram.InconsistentSnapshotBrowser",
441 std::abs(amount));
442}
443
[email protected]d01b8732008-10-16 02:18:07444void MetricsService::HandleIdleSinceLastTransmission(bool in_idle) {
445 // If there wasn't a lot of action, maybe the computer was asleep, in which
446 // case, the log transmissions should have stopped. Here we start them up
447 // again.
[email protected]cac78842008-11-27 01:02:20448 if (!in_idle && idle_since_last_transmission_)
[email protected]7f7f1962011-04-20 15:58:16449 StartSchedulerIfNecessary();
[email protected]cac78842008-11-27 01:02:20450 idle_since_last_transmission_ = in_idle;
initial.commit09911bf2008-07-26 23:55:29451}
452
[email protected]d7ea39e2014-05-22 03:59:18453void MetricsService::OnApplicationNotIdle() {
wittman622851e2015-07-31 18:13:40454 if (recording_state_ == ACTIVE)
[email protected]d7ea39e2014-05-22 03:59:18455 HandleIdleSinceLastTransmission(false);
456}
457
initial.commit09911bf2008-07-26 23:55:29458void MetricsService::RecordStartOfSessionEnd() {
holte6d341162016-12-19 21:42:42459 LogCleanShutdown(false);
initial.commit09911bf2008-07-26 23:55:29460}
461
462void MetricsService::RecordCompletedSessionEnd() {
holte6d341162016-12-19 21:42:42463 LogCleanShutdown(true);
initial.commit09911bf2008-07-26 23:55:29464}
465
[email protected]410938e02012-10-24 16:33:59466#if defined(OS_ANDROID) || defined(OS_IOS)
[email protected]117fbdf22012-06-26 18:36:39467void MetricsService::OnAppEnterBackground() {
holte68395852017-01-10 20:40:21468 if (upload_scheduler_) {
469 rotation_scheduler_->Stop();
470 upload_scheduler_->Stop();
471 } else {
472 scheduler_->Stop();
473 }
[email protected]117fbdf22012-06-26 18:36:39474
erikwright65b58df2014-09-12 00:05:28475 MarkAppCleanShutdownAndCommit(&clean_exit_beacon_, local_state_);
[email protected]117fbdf22012-06-26 18:36:39476
bmcquade6a49bed2016-07-27 19:25:56477 // Give providers a chance to persist histograms as part of being
478 // backgrounded.
479 for (MetricsProvider* provider : metrics_providers_)
480 provider->OnAppEnterBackground();
481
[email protected]117fbdf22012-06-26 18:36:39482 // At this point, there's no way of knowing when the process will be
483 // killed, so this has to be treated similar to a shutdown, closing and
484 // persisting all logs. Unlinke a shutdown, the state is primed to be ready
485 // to continue logging and uploading if the process does return.
Steven Holte2c294a32015-03-12 21:45:03486 if (recording_active() && state_ >= SENDING_LOGS) {
[email protected]117fbdf22012-06-26 18:36:39487 PushPendingLogsToPersistentStorage();
[email protected]410938e02012-10-24 16:33:59488 // Persisting logs closes the current log, so start recording a new log
489 // immediately to capture any background work that might be done before the
490 // process is killed.
491 OpenNewLog();
[email protected]117fbdf22012-06-26 18:36:39492 }
[email protected]117fbdf22012-06-26 18:36:39493}
494
495void MetricsService::OnAppEnterForeground() {
erikwright65b58df2014-09-12 00:05:28496 clean_exit_beacon_.WriteBeaconValue(false);
holtea27eadf2017-01-26 01:58:59497 ExecutionPhaseManager(local_state_).OnAppEnterForeground();
[email protected]117fbdf22012-06-26 18:36:39498 StartSchedulerIfNecessary();
499}
[email protected]84c384e2013-03-01 23:20:19500#else
erikwrightcc98a7e02014-09-09 22:05:12501void MetricsService::LogNeedForCleanShutdown() {
erikwright65b58df2014-09-12 00:05:28502 clean_exit_beacon_.WriteBeaconValue(false);
[email protected]84c384e2013-03-01 23:20:19503 // Redundant setting to be sure we call for a clean shutdown.
504 clean_shutdown_status_ = NEED_TO_SHUTDOWN;
505}
506#endif // defined(OS_ANDROID) || defined(OS_IOS)
[email protected]117fbdf22012-06-26 18:36:39507
[email protected]6d67ea0d2013-11-14 11:02:21508// static
[email protected]24f81ca2014-05-26 15:59:34509void MetricsService::SetExecutionPhase(ExecutionPhase execution_phase,
510 PrefService* local_state) {
holtea27eadf2017-01-26 01:58:59511 ExecutionPhaseManager(local_state).SetExecutionPhase(execution_phase);
[email protected]6d67ea0d2013-11-14 11:02:21512}
513
[email protected]7f7f1962011-04-20 15:58:16514void MetricsService::RecordBreakpadRegistration(bool success) {
[email protected]68475e602008-08-22 03:21:15515 if (!success)
asvitkinea63d19e2014-10-24 16:19:39516 IncrementPrefValue(prefs::kStabilityBreakpadRegistrationFail);
[email protected]e73c01972008-08-13 00:18:24517 else
asvitkinea63d19e2014-10-24 16:19:39518 IncrementPrefValue(prefs::kStabilityBreakpadRegistrationSuccess);
[email protected]e73c01972008-08-13 00:18:24519}
520
521void MetricsService::RecordBreakpadHasDebugger(bool has_debugger) {
522 if (!has_debugger)
asvitkinea63d19e2014-10-24 16:19:39523 IncrementPrefValue(prefs::kStabilityDebuggerNotPresent);
[email protected]e73c01972008-08-13 00:18:24524 else
asvitkinea63d19e2014-10-24 16:19:39525 IncrementPrefValue(prefs::kStabilityDebuggerPresent);
[email protected]e73c01972008-08-13 00:18:24526}
527
yiyaoliu14ef3ead2014-11-19 02:36:50528void MetricsService::ClearSavedStabilityMetrics() {
bcwhite34c6bbf2016-02-19 22:14:46529 for (MetricsProvider* provider : metrics_providers_)
530 provider->ClearSavedStabilityMetrics();
yiyaoliu14ef3ead2014-11-19 02:36:50531
532 // Reset the prefs that are managed by MetricsService/MetricsLog directly.
manzagop54157002016-09-01 02:43:59533 local_state_->SetInteger(prefs::kStabilityBreakpadRegistrationSuccess, 0);
534 local_state_->SetInteger(prefs::kStabilityBreakpadRegistrationFail, 0);
yiyaoliu14ef3ead2014-11-19 02:36:50535 local_state_->SetInteger(prefs::kStabilityCrashCount, 0);
manzagop54157002016-09-01 02:43:59536 local_state_->SetInteger(prefs::kStabilityDebuggerPresent, 0);
537 local_state_->SetInteger(prefs::kStabilityDebuggerNotPresent, 0);
yiyaoliu14ef3ead2014-11-19 02:36:50538 local_state_->SetInteger(prefs::kStabilityIncompleteSessionEndCount, 0);
539 local_state_->SetInteger(prefs::kStabilityLaunchCount, 0);
540 local_state_->SetBoolean(prefs::kStabilitySessionEndCompleted, true);
manzagopea99d1952016-09-08 23:40:05541 local_state_->SetInteger(prefs::kStabilityDeferredCount, 0);
542 // Note: kStabilityDiscardCount is not cleared as its intent is to measure
543 // the number of times data is discarded, even across versions.
544 local_state_->SetInteger(prefs::kStabilityVersionMismatchCount, 0);
yiyaoliu14ef3ead2014-11-19 02:36:50545}
546
olivierrobinc3dfc5b2015-04-07 19:12:00547void MetricsService::PushExternalLog(const std::string& log) {
548 log_manager_.StoreLog(log, MetricsLog::ONGOING_LOG);
549}
550
robliao7253fd22016-12-01 18:41:38551void MetricsService::UpdateMetricsUsagePrefs(const std::string& service_name,
552 int message_size,
553 bool is_cellular) {
holtea07de2062017-01-21 03:43:15554 DCHECK(thread_checker_.CalledOnValidThread());
gayane0b46091c2016-04-07 21:01:05555 if (data_use_tracker_) {
robliao7253fd22016-12-01 18:41:38556 data_use_tracker_->UpdateMetricsUsagePrefs(service_name,
557 message_size,
558 is_cellular);
gayane0b46091c2016-04-07 21:01:05559 }
gayane0b46091c2016-04-07 21:01:05560}
561
bcwhite81e14852016-08-01 19:30:23562void MetricsService::MergeHistogramDeltas() {
563 for (MetricsProvider* provider : metrics_providers_)
564 provider->MergeHistogramDeltas();
565}
566
initial.commit09911bf2008-07-26 23:55:29567//------------------------------------------------------------------------------
568// private methods
569//------------------------------------------------------------------------------
570
571
572//------------------------------------------------------------------------------
573// Initialization methods
574
[email protected]39076642014-05-05 20:32:55575void MetricsService::InitializeMetricsState() {
avi26062922015-12-26 00:14:18576 const int64_t buildtime = MetricsLog::GetBuildTime();
asvitkineff3e2a62014-09-18 22:01:49577 const std::string version = client_->GetVersionString();
holte57fcaed2017-01-23 22:14:31578
579 // Delete deprecated prefs
580 // TODO(holte): Remove these in M58
581 local_state_->ClearPref(prefs::kStabilityLaunchTimeSec);
582 local_state_->ClearPref(prefs::kStabilityLastTimestampSec);
583
asvitkineff3e2a62014-09-18 22:01:49584 bool version_changed = false;
manzagopea99d1952016-09-08 23:40:05585 int64_t previous_buildtime =
586 local_state_->GetInt64(prefs::kStabilityStatsBuildTime);
587 std::string previous_version =
588 local_state_->GetString(prefs::kStabilityStatsVersion);
589 if (previous_buildtime != buildtime || previous_version != version) {
asvitkinea63d19e2014-10-24 16:19:39590 local_state_->SetString(prefs::kStabilityStatsVersion, version);
591 local_state_->SetInt64(prefs::kStabilityStatsBuildTime, buildtime);
asvitkineff3e2a62014-09-18 22:01:49592 version_changed = true;
593 }
initial.commit09911bf2008-07-26 23:55:29594
[email protected]94dce122014-07-16 04:20:12595 log_manager_.LoadPersistedUnsentLogs();
596
asvitkinea63d19e2014-10-24 16:19:39597 session_id_ = local_state_->GetInteger(prefs::kMetricsSessionID);
erikwright65b58df2014-09-12 00:05:28598
599 if (!clean_exit_beacon_.exited_cleanly()) {
asvitkinea63d19e2014-10-24 16:19:39600 IncrementPrefValue(prefs::kStabilityCrashCount);
[email protected]c0c55e92011-09-10 18:47:30601 // Reset flag, and wait until we call LogNeedForCleanShutdown() before
602 // monitoring.
erikwright65b58df2014-09-12 00:05:28603 clean_exit_beacon_.WriteBeaconValue(true);
holtea27eadf2017-01-26 01:58:59604 ExecutionPhaseManager manager(local_state_);
manzagop7c14de22016-11-25 16:19:34605 UMA_HISTOGRAM_SPARSE_SLOWLY("Chrome.Browser.CrashedExecutionPhase",
holtea27eadf2017-01-26 01:58:59606 static_cast<int>(manager.GetExecutionPhase()));
607 manager.SetExecutionPhase(ExecutionPhase::UNINITIALIZED_PHASE);
siggic179dd062014-09-10 17:02:31608 }
[email protected]6a6d0d12013-10-28 15:58:19609
manzagop780bb8b2016-10-21 14:21:16610 // ProvidersHaveInitialStabilityMetrics is called first to ensure it is never
611 // bypassed.
612 const bool is_initial_stability_log_required =
613 ProvidersHaveInitialStabilityMetrics() ||
614 !clean_exit_beacon_.exited_cleanly();
Steven Holte2c294a32015-03-12 21:45:03615 bool has_initial_stability_log = false;
manzagop780bb8b2016-10-21 14:21:16616 if (is_initial_stability_log_required) {
siggic179dd062014-09-10 17:02:31617 // If the previous session didn't exit cleanly, or if any provider
618 // explicitly requests it, prepare an initial stability log -
619 // provided UMA is enabled.
manzagopea99d1952016-09-08 23:40:05620 if (state_manager_->IsMetricsReportingEnabled()) {
621 has_initial_stability_log = PrepareInitialStabilityLog(previous_version);
622 if (!has_initial_stability_log)
623 IncrementPrefValue(prefs::kStabilityDeferredCount);
624 }
initial.commit09911bf2008-07-26 23:55:29625 }
[email protected]80a8f312013-12-16 18:00:30626
manzagop780bb8b2016-10-21 14:21:16627 // If the version changed, but no initial stability log was generated, clear
628 // the stability stats from the previous version (so that they don't get
asvitkineff3e2a62014-09-18 22:01:49629 // attributed to the current version). This could otherwise happen due to a
630 // number of different edge cases, such as if the last version crashed before
631 // it could save off a system profile or if UMA reporting is disabled (which
632 // normally results in stats being accumulated).
manzagop780bb8b2016-10-21 14:21:16633 if (version_changed && !has_initial_stability_log) {
yiyaoliu14ef3ead2014-11-19 02:36:50634 ClearSavedStabilityMetrics();
manzagopea99d1952016-09-08 23:40:05635 IncrementPrefValue(prefs::kStabilityDiscardCount);
636 }
asvitkineff3e2a62014-09-18 22:01:49637
manzagop780bb8b2016-10-21 14:21:16638 // If the version changed, the system profile is obsolete and needs to be
639 // cleared. This is to avoid the stability data misattribution that could
640 // occur if the current version crashed before saving its own system profile.
641 // Note however this clearing occurs only after preparing the initial
642 // stability log, an operation that requires the previous version's system
643 // profile. At this point, stability metrics pertaining to the previous
644 // version have been cleared.
645 if (version_changed) {
646 local_state_->ClearPref(prefs::kStabilitySavedSystemProfile);
647 local_state_->ClearPref(prefs::kStabilitySavedSystemProfileHash);
648 }
649
[email protected]80a8f312013-12-16 18:00:30650 // Update session ID.
651 ++session_id_;
asvitkinea63d19e2014-10-24 16:19:39652 local_state_->SetInteger(prefs::kMetricsSessionID, session_id_);
[email protected]80a8f312013-12-16 18:00:30653
654 // Stability bookkeeping
asvitkinea63d19e2014-10-24 16:19:39655 IncrementPrefValue(prefs::kStabilityLaunchCount);
[email protected]80a8f312013-12-16 18:00:30656
holtea27eadf2017-01-26 01:58:59657 SetExecutionPhase(ExecutionPhase::START_METRICS_RECORDING, local_state_);
[email protected]e73c01972008-08-13 00:18:24658
asvitkinea63d19e2014-10-24 16:19:39659 if (!local_state_->GetBoolean(prefs::kStabilitySessionEndCompleted)) {
660 IncrementPrefValue(prefs::kStabilityIncompleteSessionEndCount);
[email protected]c9abf242009-07-18 06:00:38661 // This is marked false when we get a WM_ENDSESSION.
asvitkinea63d19e2014-10-24 16:19:39662 local_state_->SetBoolean(prefs::kStabilitySessionEndCompleted, true);
initial.commit09911bf2008-07-26 23:55:29663 }
initial.commit09911bf2008-07-26 23:55:29664
[email protected]076961c2014-03-12 22:23:56665 // Call GetUptimes() for the first time, thus allowing all later calls
666 // to record incremental uptimes accurately.
667 base::TimeDelta ignored_uptime_parameter;
668 base::TimeDelta startup_uptime;
[email protected]24f81ca2014-05-26 15:59:34669 GetUptimes(local_state_, &startup_uptime, &ignored_uptime_parameter);
[email protected]c68a2b9b2013-10-09 18:16:36670 DCHECK_EQ(0, startup_uptime.InMicroseconds());
[email protected]0bb1a622009-03-04 03:22:32671
672 // Bookkeeping for the uninstall metrics.
asvitkinea63d19e2014-10-24 16:19:39673 IncrementLongPrefsValue(prefs::kUninstallLaunchCount);
initial.commit09911bf2008-07-26 23:55:29674}
675
[email protected]dd98f392013-02-04 13:03:22676void MetricsService::OnUserAction(const std::string& action) {
[email protected]4426d2d2014-04-09 12:33:00677 log_manager_.current_log()->RecordUserAction(action);
[email protected]dd98f392013-02-04 13:03:22678 HandleIdleSinceLastTransmission(false);
679}
680
ishermanb6705682015-08-29 00:01:00681void MetricsService::FinishedInitTask() {
[email protected]ed0fd002012-04-25 23:10:34682 DCHECK_EQ(INIT_TASK_SCHEDULED, state_);
[email protected]c68a2b9b2013-10-09 18:16:36683 state_ = INIT_TASK_DONE;
[email protected]83d09f92014-06-03 14:58:26684
685 // Create the initial log.
686 if (!initial_metrics_log_.get()) {
687 initial_metrics_log_ = CreateLog(MetricsLog::ONGOING_LOG);
688 NotifyOnDidCreateMetricsLog();
689 }
690
holte68395852017-01-10 20:40:21691 if (upload_scheduler_) {
692 rotation_scheduler_->InitTaskComplete();
693 } else {
694 scheduler_->InitTaskComplete();
695 }
[email protected]c68a2b9b2013-10-09 18:16:36696}
697
[email protected]076961c2014-03-12 22:23:56698void MetricsService::GetUptimes(PrefService* pref,
699 base::TimeDelta* incremental_uptime,
700 base::TimeDelta* uptime) {
[email protected]c68a2b9b2013-10-09 18:16:36701 base::TimeTicks now = base::TimeTicks::Now();
[email protected]076961c2014-03-12 22:23:56702 // If this is the first call, init |first_updated_time_| and
703 // |last_updated_time_|.
704 if (last_updated_time_.is_null()) {
705 first_updated_time_ = now;
[email protected]c68a2b9b2013-10-09 18:16:36706 last_updated_time_ = now;
[email protected]076961c2014-03-12 22:23:56707 }
708 *incremental_uptime = now - last_updated_time_;
709 *uptime = now - first_updated_time_;
[email protected]c68a2b9b2013-10-09 18:16:36710 last_updated_time_ = now;
711
avi26062922015-12-26 00:14:18712 const int64_t incremental_time_secs = incremental_uptime->InSeconds();
[email protected]c68a2b9b2013-10-09 18:16:36713 if (incremental_time_secs > 0) {
avi26062922015-12-26 00:14:18714 int64_t metrics_uptime = pref->GetInt64(prefs::kUninstallMetricsUptimeSec);
[email protected]c68a2b9b2013-10-09 18:16:36715 metrics_uptime += incremental_time_secs;
asvitkinea63d19e2014-10-24 16:19:39716 pref->SetInt64(prefs::kUninstallMetricsUptimeSec, metrics_uptime);
[email protected]c68a2b9b2013-10-09 18:16:36717 }
initial.commit09911bf2008-07-26 23:55:29718}
719
[email protected]2a321de32014-05-10 19:59:06720void MetricsService::NotifyOnDidCreateMetricsLog() {
holtea07de2062017-01-21 03:43:15721 DCHECK(thread_checker_.CalledOnValidThread());
bcwhite34c6bbf2016-02-19 22:14:46722 for (MetricsProvider* provider : metrics_providers_)
723 provider->OnDidCreateMetricsLog();
[email protected]2a321de32014-05-10 19:59:06724}
725
initial.commit09911bf2008-07-26 23:55:29726
727//------------------------------------------------------------------------------
728// Recording control methods
729
[email protected]410938e02012-10-24 16:33:59730void MetricsService::OpenNewLog() {
731 DCHECK(!log_manager_.current_log());
initial.commit09911bf2008-07-26 23:55:29732
[email protected]bfb77b52014-06-07 01:54:01733 log_manager_.BeginLoggingWithLog(CreateLog(MetricsLog::ONGOING_LOG));
[email protected]2a321de32014-05-10 19:59:06734 NotifyOnDidCreateMetricsLog();
initial.commit09911bf2008-07-26 23:55:29735 if (state_ == INITIALIZED) {
736 // We only need to schedule that run once.
[email protected]85ed9d42010-06-08 22:37:44737 state_ = INIT_TASK_SCHEDULED;
initial.commit09911bf2008-07-26 23:55:29738
skyostilb0daa012015-06-02 19:03:48739 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
ishermanb6705682015-08-29 00:01:00740 FROM_HERE, base::Bind(&MetricsService::StartInitTask,
skyostilb0daa012015-06-02 19:03:48741 self_ptr_factory_.GetWeakPtr()),
[email protected]7e560102012-03-08 20:58:42742 base::TimeDelta::FromSeconds(kInitializationDelaySeconds));
initial.commit09911bf2008-07-26 23:55:29743 }
744}
745
ishermanb6705682015-08-29 00:01:00746void MetricsService::StartInitTask() {
747 client_->InitializeSystemProfileMetrics(
748 base::Bind(&MetricsService::FinishedInitTask,
[email protected]51994b22014-05-30 13:24:21749 self_ptr_factory_.GetWeakPtr()));
750}
751
[email protected]410938e02012-10-24 16:33:59752void MetricsService::CloseCurrentLog() {
[email protected]cac267c2011-09-29 15:18:10753 if (!log_manager_.current_log())
initial.commit09911bf2008-07-26 23:55:29754 return;
755
rkaplow02e248432017-01-20 23:39:41756 // TODO(rkaplow): Evaluate if this is needed.
[email protected]cac267c2011-09-29 15:18:10757 if (log_manager_.current_log()->num_events() > kEventLimit) {
[email protected]553dba62009-02-24 19:08:23758 UMA_HISTOGRAM_COUNTS("UMA.Discarded Log Events",
[email protected]cac267c2011-09-29 15:18:10759 log_manager_.current_log()->num_events());
rkaplow02e248432017-01-20 23:39:41760 if (base::FeatureList::IsEnabled(kUMAThrottleEvents)) {
761 log_manager_.DiscardCurrentLog();
762 OpenNewLog(); // Start trivial log to hold our histograms.
763 }
[email protected]68475e602008-08-22 03:21:15764 }
765
bcwhite5cb99eb2016-02-01 21:07:56766 // If a persistent allocator is in use, update its internal histograms (such
767 // as how much memory is being used) before reporting.
bcwhite33d95806a2016-03-16 02:37:45768 base::PersistentHistogramAllocator* allocator =
bcwhite5e748c62016-04-06 02:03:53769 base::GlobalHistogramAllocator::Get();
bcwhite5cb99eb2016-02-01 21:07:56770 if (allocator)
771 allocator->UpdateTrackingHistograms();
772
[email protected]0b33f80b2008-12-17 21:34:36773 // Put incremental data (histogram deltas, and realtime stats deltas) at the
[email protected]147bbc0b2009-01-06 19:37:40774 // end of all log transmissions (initial log handles this separately).
[email protected]024b5cd2011-05-27 03:29:38775 // RecordIncrementalStabilityElements only exists on the derived
776 // MetricsLog class.
[email protected]94dce122014-07-16 04:20:12777 MetricsLog* current_log = log_manager_.current_log();
[email protected]024b5cd2011-05-27 03:29:38778 DCHECK(current_log);
asvitkine88aa9332014-09-29 23:29:17779 RecordCurrentEnvironment(current_log);
[email protected]076961c2014-03-12 22:23:56780 base::TimeDelta incremental_uptime;
781 base::TimeDelta uptime;
[email protected]24f81ca2014-05-26 15:59:34782 GetUptimes(local_state_, &incremental_uptime, &uptime);
[email protected]85791b0b2014-05-20 15:18:58783 current_log->RecordStabilityMetrics(metrics_providers_.get(),
784 incremental_uptime, uptime);
[email protected]60677562013-11-17 15:52:55785
[email protected]85791b0b2014-05-20 15:18:58786 current_log->RecordGeneralMetrics(metrics_providers_.get());
mariakhomenko191028982014-10-20 23:22:56787 RecordCurrentHistograms();
initial.commit09911bf2008-07-26 23:55:29788
[email protected]29948262012-03-01 12:15:08789 log_manager_.FinishCurrentLog();
initial.commit09911bf2008-07-26 23:55:29790}
791
[email protected]cac267c2011-09-29 15:18:10792void MetricsService::PushPendingLogsToPersistentStorage() {
Steven Holte2c294a32015-03-12 21:45:03793 if (state_ < SENDING_LOGS)
[email protected]28ab7f92009-01-06 21:39:04794 return; // We didn't and still don't have time to get plugin list etc.
initial.commit09911bf2008-07-26 23:55:29795
[email protected]410938e02012-10-24 16:33:59796 CloseCurrentLog();
[email protected]80a8f312013-12-16 18:00:30797 log_manager_.PersistUnsentLogs();
initial.commit09911bf2008-07-26 23:55:29798}
799
800//------------------------------------------------------------------------------
801// Transmission of logs methods
802
[email protected]7f7f1962011-04-20 15:58:16803void MetricsService::StartSchedulerIfNecessary() {
[email protected]410938e02012-10-24 16:33:59804 // Never schedule cutting or uploading of logs in test mode.
805 if (test_mode_active_)
806 return;
807
808 // Even if reporting is disabled, the scheduler is needed to trigger the
809 // creation of the initial log, which must be done in order for any logs to be
810 // persisted on shutdown or backgrounding.
[email protected]80a8f312013-12-16 18:00:30811 if (recording_active() &&
Steven Holte2c294a32015-03-12 21:45:03812 (reporting_active() || state_ < SENDING_LOGS)) {
holte68395852017-01-10 20:40:21813 if (upload_scheduler_) {
814 rotation_scheduler_->Start();
815 upload_scheduler_->Start();
816 } else {
817 scheduler_->Start();
818 }
[email protected]80a8f312013-12-16 18:00:30819 }
initial.commit09911bf2008-07-26 23:55:29820}
821
[email protected]7f7f1962011-04-20 15:58:16822void MetricsService::StartScheduledUpload() {
holtea6a39172015-03-25 19:57:20823 DCHECK(state_ >= INIT_TASK_DONE);
[email protected]cd1ac712012-06-26 08:26:47824 // If we're getting no notifications, then the log won't have much in it, and
825 // it's possible the computer is about to go to sleep, so don't upload and
826 // stop the scheduler.
[email protected]410938e02012-10-24 16:33:59827 // If recording has been turned off, the scheduler doesn't need to run.
828 // If reporting is off, proceed if the initial log hasn't been created, since
829 // that has to happen in order for logs to be cut and stored when persisting.
[email protected]d7ea39e2014-05-22 03:59:18830 // TODO(stuartmorgan): Call Stop() on the scheduler when reporting and/or
[email protected]cd1ac712012-06-26 08:26:47831 // recording are turned off instead of letting it fire and then aborting.
832 if (idle_since_last_transmission_ ||
[email protected]410938e02012-10-24 16:33:59833 !recording_active() ||
Steven Holte2c294a32015-03-12 21:45:03834 (!reporting_active() && state_ >= SENDING_LOGS)) {
holte68395852017-01-10 20:40:21835 if (upload_scheduler_) {
836 rotation_scheduler_->Stop();
837 rotation_scheduler_->RotationFinished();
838 } else {
839 scheduler_->Stop();
840 scheduler_->UploadCancelled();
841 }
[email protected]7f7f1962011-04-20 15:58:16842 return;
843 }
844
[email protected]cd1ac712012-06-26 08:26:47845 // If there are unsent logs, send the next one. If not, start the asynchronous
846 // process of finalizing the current log for upload.
Steven Holte2c294a32015-03-12 21:45:03847 if (state_ == SENDING_LOGS && log_manager_.has_unsent_logs()) {
holte68395852017-01-10 20:40:21848 if (upload_scheduler_) {
849 upload_scheduler_->Start();
850 rotation_scheduler_->RotationFinished();
851 } else {
852 SendNextLog();
853 }
[email protected]cd1ac712012-06-26 08:26:47854 } else {
holtea6a39172015-03-25 19:57:20855 // There are no logs left to send, so start creating a new one.
ishermanb6705682015-08-29 00:01:00856 client_->CollectFinalMetricsForLog(
[email protected]4b4892b2014-05-22 15:06:15857 base::Bind(&MetricsService::OnFinalLogInfoCollectionDone,
858 self_ptr_factory_.GetWeakPtr()));
[email protected]cd1ac712012-06-26 08:26:47859 }
[email protected]29948262012-03-01 12:15:08860}
861
[email protected]29948262012-03-01 12:15:08862void MetricsService::OnFinalLogInfoCollectionDone() {
[email protected]0d5a61a82014-05-31 22:28:34863 // If somehow there is a log upload in progress, we return and hope things
864 // work out. The scheduler isn't informed since if this happens, the scheduler
[email protected]7f7f1962011-04-20 15:58:16865 // will get a response from the upload.
[email protected]0d5a61a82014-05-31 22:28:34866 DCHECK(!log_upload_in_progress_);
867 if (log_upload_in_progress_)
[email protected]7f7f1962011-04-20 15:58:16868 return;
869
[email protected]cd1ac712012-06-26 08:26:47870 // Abort if metrics were turned off during the final info gathering.
[email protected]410938e02012-10-24 16:33:59871 if (!recording_active()) {
holte68395852017-01-10 20:40:21872 if (upload_scheduler_) {
873 rotation_scheduler_->Stop();
874 rotation_scheduler_->RotationFinished();
875 } else {
876 scheduler_->Stop();
877 scheduler_->UploadCancelled();
878 }
[email protected]d01b8732008-10-16 02:18:07879 return;
880 }
881
holtea6a39172015-03-25 19:57:20882 if (state_ == INIT_TASK_DONE) {
883 PrepareInitialMetricsLog();
884 } else {
885 DCHECK_EQ(SENDING_LOGS, state_);
886 CloseCurrentLog();
887 OpenNewLog();
888 }
holte68395852017-01-10 20:40:21889 if (upload_scheduler_) {
890 upload_scheduler_->Start();
891 rotation_scheduler_->RotationFinished();
892 } else {
893 SendNextLog();
894 }
holtea6a39172015-03-25 19:57:20895}
[email protected]410938e02012-10-24 16:33:59896
holtea6a39172015-03-25 19:57:20897void MetricsService::SendNextLog() {
898 DCHECK_EQ(SENDING_LOGS, state_);
[email protected]410938e02012-10-24 16:33:59899 if (!reporting_active()) {
holte68395852017-01-10 20:40:21900 if (upload_scheduler_) {
901 upload_scheduler_->Stop();
902 upload_scheduler_->UploadCancelled();
903 } else {
904 scheduler_->Stop();
905 scheduler_->UploadCancelled();
906 }
[email protected]410938e02012-10-24 16:33:59907 return;
908 }
holtea6a39172015-03-25 19:57:20909 if (!log_manager_.has_unsent_logs()) {
910 // Should only get here if serializing the log failed somehow.
holte68395852017-01-10 20:40:21911 if (upload_scheduler_) {
912 upload_scheduler_->Stop();
913 // Reset backoff interval
914 upload_scheduler_->UploadFinished(true);
915 } else {
916 // Just tell the scheduler it was uploaded and wait for the next log
917 // interval.
918 scheduler_->UploadFinished(true, log_manager_.has_unsent_logs());
919 }
[email protected]29948262012-03-01 12:15:08920 return;
[email protected]29948262012-03-01 12:15:08921 }
holtea6a39172015-03-25 19:57:20922 if (!log_manager_.has_staged_log())
923 log_manager_.StageNextLogForUpload();
gayane0b46091c2016-04-07 21:01:05924
925 // Proceed to stage the log for upload if log size satisfies cellular log
926 // upload constrains.
gayane0417f9782016-04-11 19:34:06927 bool upload_canceled = false;
928 bool is_cellular_logic = client_->IsUMACellularUploadLogicEnabled();
gayanea6c9bd12016-04-14 15:51:16929 if (is_cellular_logic && data_use_tracker_ &&
gayane0b46091c2016-04-07 21:01:05930 !data_use_tracker_->ShouldUploadLogOnCellular(
931 log_manager_.staged_log_hash().size())) {
holte68395852017-01-10 20:40:21932 if (upload_scheduler_) {
933 upload_scheduler_->UploadOverDataUsageCap();
934 } else {
935 scheduler_->UploadCancelled();
936 }
gayane0417f9782016-04-11 19:34:06937 upload_canceled = true;
gayane0b46091c2016-04-07 21:01:05938 } else {
939 SendStagedLog();
940 }
gayane0417f9782016-04-11 19:34:06941 if (is_cellular_logic) {
942 UMA_HISTOGRAM_BOOLEAN("UMA.LogUpload.Canceled.CellularConstraint",
943 upload_canceled);
944 }
[email protected]29948262012-03-01 12:15:08945}
946
lpromeroca8cb6f2015-04-30 18:16:53947bool MetricsService::ProvidersHaveInitialStabilityMetrics() {
948 // Check whether any metrics provider has initial stability metrics.
bcwhite02ca7452016-11-29 21:54:07949 // All providers are queried (rather than stopping after the first "true"
950 // response) in case they do any kind of setup work in preparation for
951 // the later call to RecordInitialHistogramSnapshots().
952 bool has_stability_metrics = false;
953 for (MetricsProvider* provider : metrics_providers_)
954 has_stability_metrics |= provider->HasInitialStabilityMetrics();
siggic179dd062014-09-10 17:02:31955
bcwhite02ca7452016-11-29 21:54:07956 return has_stability_metrics;
siggic179dd062014-09-10 17:02:31957}
958
manzagopea99d1952016-09-08 23:40:05959bool MetricsService::PrepareInitialStabilityLog(
960 const std::string& prefs_previous_version) {
[email protected]80a8f312013-12-16 18:00:30961 DCHECK_EQ(INITIALIZED, state_);
[email protected]29948262012-03-01 12:15:08962
dchengd99c42a2016-04-21 21:54:13963 std::unique_ptr<MetricsLog> initial_stability_log(
[email protected]09dee82d2014-05-22 14:00:53964 CreateLog(MetricsLog::INITIAL_STABILITY_LOG));
[email protected]2a321de32014-05-10 19:59:06965
966 // Do not call NotifyOnDidCreateMetricsLog here because the stability
967 // log describes stats from the _previous_ session.
manzagopea99d1952016-09-08 23:40:05968 std::string system_profile_app_version;
969 if (!initial_stability_log->LoadSavedEnvironmentFromPrefs(
970 &system_profile_app_version)) {
Steven Holte2c294a32015-03-12 21:45:03971 return false;
manzagopea99d1952016-09-08 23:40:05972 }
973 if (system_profile_app_version != prefs_previous_version)
974 IncrementPrefValue(prefs::kStabilityVersionMismatchCount);
[email protected]85791b0b2014-05-20 15:18:58975
[email protected]80a8f312013-12-16 18:00:30976 log_manager_.PauseCurrentLog();
dcheng51606352015-12-26 21:16:23977 log_manager_.BeginLoggingWithLog(std::move(initial_stability_log));
[email protected]85791b0b2014-05-20 15:18:58978
979 // Note: Some stability providers may record stability stats via histograms,
980 // so this call has to be after BeginLoggingWithLog().
[email protected]bfb77b52014-06-07 01:54:01981 log_manager_.current_log()->RecordStabilityMetrics(
982 metrics_providers_.get(), base::TimeDelta(), base::TimeDelta());
[email protected]c778687a2014-02-11 14:46:45983 RecordCurrentStabilityHistograms();
[email protected]85791b0b2014-05-20 15:18:58984
985 // Note: RecordGeneralMetrics() intentionally not called since this log is for
986 // stability stats from a previous session only.
987
[email protected]80a8f312013-12-16 18:00:30988 log_manager_.FinishCurrentLog();
989 log_manager_.ResumePausedLog();
990
991 // Store unsent logs, including the stability log that was just saved, so
992 // that they're not lost in case of a crash before upload time.
993 log_manager_.PersistUnsentLogs();
994
Steven Holte2c294a32015-03-12 21:45:03995 return true;
[email protected]80a8f312013-12-16 18:00:30996}
997
[email protected]b58b8b22014-04-08 22:40:33998void MetricsService::PrepareInitialMetricsLog() {
Steven Holte2c294a32015-03-12 21:45:03999 DCHECK_EQ(INIT_TASK_DONE, state_);
[email protected]0edf8762013-11-21 18:33:301000
asvitkine88aa9332014-09-29 23:29:171001 RecordCurrentEnvironment(initial_metrics_log_.get());
[email protected]076961c2014-03-12 22:23:561002 base::TimeDelta incremental_uptime;
1003 base::TimeDelta uptime;
[email protected]24f81ca2014-05-26 15:59:341004 GetUptimes(local_state_, &incremental_uptime, &uptime);
[email protected]29948262012-03-01 12:15:081005
1006 // Histograms only get written to the current log, so make the new log current
1007 // before writing them.
1008 log_manager_.PauseCurrentLog();
dcheng51606352015-12-26 21:16:231009 log_manager_.BeginLoggingWithLog(std::move(initial_metrics_log_));
[email protected]85791b0b2014-05-20 15:18:581010
1011 // Note: Some stability providers may record stability stats via histograms,
1012 // so this call has to be after BeginLoggingWithLog().
[email protected]94dce122014-07-16 04:20:121013 MetricsLog* current_log = log_manager_.current_log();
[email protected]85791b0b2014-05-20 15:18:581014 current_log->RecordStabilityMetrics(metrics_providers_.get(),
1015 base::TimeDelta(), base::TimeDelta());
[email protected]85791b0b2014-05-20 15:18:581016 current_log->RecordGeneralMetrics(metrics_providers_.get());
mariakhomenko191028982014-10-20 23:22:561017 RecordCurrentHistograms();
[email protected]85791b0b2014-05-20 15:18:581018
[email protected]29948262012-03-01 12:15:081019 log_manager_.FinishCurrentLog();
1020 log_manager_.ResumePausedLog();
1021
[email protected]94dce122014-07-16 04:20:121022 // Store unsent logs, including the initial log that was just saved, so
1023 // that they're not lost in case of a crash before upload time.
1024 log_manager_.PersistUnsentLogs();
holtea6a39172015-03-25 19:57:201025
1026 state_ = SENDING_LOGS;
[email protected]29948262012-03-01 12:15:081027}
1028
[email protected]29948262012-03-01 12:15:081029void MetricsService::SendStagedLog() {
1030 DCHECK(log_manager_.has_staged_log());
[email protected]0d5a61a82014-05-31 22:28:341031 if (!log_manager_.has_staged_log())
1032 return;
[email protected]29948262012-03-01 12:15:081033
[email protected]0d5a61a82014-05-31 22:28:341034 DCHECK(!log_upload_in_progress_);
1035 log_upload_in_progress_ = true;
[email protected]d01b8732008-10-16 02:18:071036
[email protected]0d5a61a82014-05-31 22:28:341037 if (!log_uploader_) {
1038 log_uploader_ = client_->CreateUploader(
holte567a16f22017-01-06 01:53:451039 client_->GetMetricsServerUrl(),
1040 metrics::kDefaultMetricsMimeType,
[email protected]0d5a61a82014-05-31 22:28:341041 base::Bind(&MetricsService::OnLogUploadComplete,
1042 self_ptr_factory_.GetWeakPtr()));
1043 }
1044
1045 const std::string hash =
1046 base::HexEncode(log_manager_.staged_log_hash().data(),
1047 log_manager_.staged_log_hash().size());
ishermana6727522015-08-06 22:28:491048 log_uploader_->UploadLog(log_manager_.staged_log(), hash);
[email protected]d01b8732008-10-16 02:18:071049
[email protected]d01b8732008-10-16 02:18:071050 HandleIdleSinceLastTransmission(true);
1051}
1052
[email protected]cac78842008-11-27 01:02:201053
[email protected]0d5a61a82014-05-31 22:28:341054void MetricsService::OnLogUploadComplete(int response_code) {
Steven Holte2c294a32015-03-12 21:45:031055 DCHECK_EQ(SENDING_LOGS, state_);
[email protected]0d5a61a82014-05-31 22:28:341056 DCHECK(log_upload_in_progress_);
1057 log_upload_in_progress_ = false;
[email protected]fe58acc22012-02-29 01:29:581058
[email protected]dc61fe92012-06-12 00:13:501059 // Log a histogram to track response success vs. failure rates.
[email protected]e3eb0c42013-04-18 06:18:581060 UMA_HISTOGRAM_ENUMERATION("UMA.UploadResponseStatus.Protobuf",
1061 ResponseCodeToStatus(response_code),
1062 NUM_RESPONSE_STATUSES);
[email protected]fe58acc22012-02-29 01:29:581063
[email protected]dc61fe92012-06-12 00:13:501064 bool upload_succeeded = response_code == 200;
[email protected]7f7f1962011-04-20 15:58:161065
[email protected]0eb34fee2009-01-21 08:04:381066 // Provide boolean for error recovery (allow us to ignore response_code).
[email protected]dc6f4962009-02-13 01:25:501067 bool discard_log = false;
[email protected]7f07db62014-05-15 01:12:451068 const size_t log_size = log_manager_.staged_log().length();
asvitkined80ebf6c2014-09-02 22:29:111069 if (upload_succeeded) {
1070 UMA_HISTOGRAM_COUNTS_10000("UMA.LogSize.OnSuccess", log_size / 1024);
1071 } else if (log_size > kUploadLogAvoidRetransmitSize) {
[email protected]dc61fe92012-06-12 00:13:501072 UMA_HISTOGRAM_COUNTS("UMA.Large Rejected Log was Discarded",
1073 static_cast<int>(log_size));
[email protected]0eb34fee2009-01-21 08:04:381074 discard_log = true;
[email protected]dc61fe92012-06-12 00:13:501075 } else if (response_code == 400) {
[email protected]0eb34fee2009-01-21 08:04:381076 // Bad syntax. Retransmission won't work.
[email protected]0eb34fee2009-01-21 08:04:381077 discard_log = true;
[email protected]68475e602008-08-22 03:21:151078 }
1079
[email protected]94dce122014-07-16 04:20:121080 if (upload_succeeded || discard_log) {
[email protected]5f3e1642013-05-05 03:37:341081 log_manager_.DiscardStagedLog();
[email protected]94dce122014-07-16 04:20:121082 // Store the updated list to disk now that the removed log is uploaded.
1083 log_manager_.PersistUnsentLogs();
1084 }
[email protected]dc61fe92012-06-12 00:13:501085
[email protected]7f7f1962011-04-20 15:58:161086 // Error 400 indicates a problem with the log, not with the server, so
1087 // don't consider that a sign that the server is in trouble.
[email protected]dc61fe92012-06-12 00:13:501088 bool server_is_healthy = upload_succeeded || response_code == 400;
holte68395852017-01-10 20:40:211089 if (upload_scheduler_) {
1090 if (!log_manager_.has_unsent_logs()) {
1091 upload_scheduler_->Stop();
1092 }
1093 upload_scheduler_->UploadFinished(server_is_healthy);
1094 } else {
1095 scheduler_->UploadFinished(server_is_healthy,
1096 log_manager_.has_unsent_logs());
1097 }
initial.commit09911bf2008-07-26 23:55:291098}
1099
[email protected]57ecc4b2010-08-11 03:02:511100void MetricsService::IncrementPrefValue(const char* path) {
[email protected]24f81ca2014-05-26 15:59:341101 int value = local_state_->GetInteger(path);
1102 local_state_->SetInteger(path, value + 1);
[email protected]e73c01972008-08-13 00:18:241103}
1104
[email protected]57ecc4b2010-08-11 03:02:511105void MetricsService::IncrementLongPrefsValue(const char* path) {
avi26062922015-12-26 00:14:181106 int64_t value = local_state_->GetInt64(path);
[email protected]24f81ca2014-05-26 15:59:341107 local_state_->SetInt64(path, value + 1);
[email protected]0bb1a622009-03-04 03:22:321108}
1109
[email protected]c0c55e92011-09-10 18:47:301110bool MetricsService::UmaMetricsProperlyShutdown() {
1111 CHECK(clean_shutdown_status_ == CLEANLY_SHUTDOWN ||
1112 clean_shutdown_status_ == NEED_TO_SHUTDOWN);
1113 return clean_shutdown_status_ == CLEANLY_SHUTDOWN;
1114}
1115
asvitkinee0dbdbe2014-10-31 21:59:571116void MetricsService::AddSyntheticTrialObserver(
asvitkine9a279832015-12-18 02:35:501117 variations::SyntheticTrialObserver* observer) {
asvitkinee0dbdbe2014-10-31 21:59:571118 synthetic_trial_observer_list_.AddObserver(observer);
1119 if (!synthetic_trial_groups_.empty())
1120 observer->OnSyntheticTrialsChanged(synthetic_trial_groups_);
1121}
1122
1123void MetricsService::RemoveSyntheticTrialObserver(
asvitkine9a279832015-12-18 02:35:501124 variations::SyntheticTrialObserver* observer) {
asvitkinee0dbdbe2014-10-31 21:59:571125 synthetic_trial_observer_list_.RemoveObserver(observer);
1126}
1127
[email protected]60677562013-11-17 15:52:551128void MetricsService::RegisterSyntheticFieldTrial(
asvitkine9a279832015-12-18 02:35:501129 const variations::SyntheticTrialGroup& trial) {
[email protected]60677562013-11-17 15:52:551130 for (size_t i = 0; i < synthetic_trial_groups_.size(); ++i) {
1131 if (synthetic_trial_groups_[i].id.name == trial.id.name) {
1132 if (synthetic_trial_groups_[i].id.group != trial.id.group) {
1133 synthetic_trial_groups_[i].id.group = trial.id.group;
[email protected]7a5c07812014-02-26 11:45:411134 synthetic_trial_groups_[i].start_time = base::TimeTicks::Now();
asvitkinee0dbdbe2014-10-31 21:59:571135 NotifySyntheticTrialObservers();
[email protected]60677562013-11-17 15:52:551136 }
1137 return;
1138 }
1139 }
1140
asvitkine9a279832015-12-18 02:35:501141 variations::SyntheticTrialGroup trial_group = trial;
[email protected]7a5c07812014-02-26 11:45:411142 trial_group.start_time = base::TimeTicks::Now();
[email protected]60677562013-11-17 15:52:551143 synthetic_trial_groups_.push_back(trial_group);
asvitkinee0dbdbe2014-10-31 21:59:571144 NotifySyntheticTrialObservers();
[email protected]60677562013-11-17 15:52:551145}
1146
asvitkine6a1c8812016-08-01 22:37:011147void MetricsService::RegisterSyntheticMultiGroupFieldTrial(
1148 uint32_t trial_name_hash,
1149 const std::vector<uint32_t>& group_name_hashes) {
1150 auto has_same_trial_name =
1151 [trial_name_hash](const variations::SyntheticTrialGroup& x) {
1152 return x.id.name == trial_name_hash;
1153 };
1154 synthetic_trial_groups_.erase(
1155 std::remove_if(synthetic_trial_groups_.begin(),
1156 synthetic_trial_groups_.end(), has_same_trial_name),
1157 synthetic_trial_groups_.end());
1158
1159 if (group_name_hashes.empty())
1160 return;
1161
1162 variations::SyntheticTrialGroup trial_group(trial_name_hash,
1163 group_name_hashes[0]);
1164 trial_group.start_time = base::TimeTicks::Now();
1165 for (uint32_t group_name_hash : group_name_hashes) {
1166 // Note: Adding the trial group will copy it, so this re-uses the same
1167 // |trial_group| struct for convenience (e.g. so start_time's all match).
1168 trial_group.id.group = group_name_hash;
1169 synthetic_trial_groups_.push_back(trial_group);
1170 }
1171 NotifySyntheticTrialObservers();
1172}
1173
nasko7d4c2cb2015-11-26 01:29:351174void MetricsService::GetCurrentSyntheticFieldTrialsForTesting(
1175 std::vector<variations::ActiveGroupId>* synthetic_trials) {
1176 GetSyntheticFieldTrialsOlderThan(base::TimeTicks::Now(), synthetic_trials);
1177}
1178
[email protected]85791b0b2014-05-20 15:18:581179void MetricsService::RegisterMetricsProvider(
dchengd99c42a2016-04-21 21:54:131180 std::unique_ptr<MetricsProvider> provider) {
[email protected]85791b0b2014-05-20 15:18:581181 DCHECK_EQ(INITIALIZED, state_);
dcheng51606352015-12-26 21:16:231182 metrics_providers_.push_back(std::move(provider));
[email protected]85791b0b2014-05-20 15:18:581183}
1184
[email protected]61b0d482014-05-20 14:49:101185void MetricsService::CheckForClonedInstall(
1186 scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
1187 state_manager_->CheckForClonedInstall(task_runner);
[email protected]99c892d2014-03-24 18:11:211188}
1189
asvitkinee0dbdbe2014-10-31 21:59:571190void MetricsService::NotifySyntheticTrialObservers() {
ericwilligersa22488d42016-10-25 01:20:571191 for (variations::SyntheticTrialObserver& observer :
1192 synthetic_trial_observer_list_) {
1193 observer.OnSyntheticTrialsChanged(synthetic_trial_groups_);
1194 }
asvitkinee0dbdbe2014-10-31 21:59:571195}
1196
nasko7d4c2cb2015-11-26 01:29:351197void MetricsService::GetSyntheticFieldTrialsOlderThan(
1198 base::TimeTicks time,
[email protected]b3610d42014-05-19 18:07:231199 std::vector<variations::ActiveGroupId>* synthetic_trials) {
[email protected]60677562013-11-17 15:52:551200 DCHECK(synthetic_trials);
1201 synthetic_trials->clear();
[email protected]60677562013-11-17 15:52:551202 for (size_t i = 0; i < synthetic_trial_groups_.size(); ++i) {
nasko7d4c2cb2015-11-26 01:29:351203 if (synthetic_trial_groups_[i].start_time <= time)
[email protected]60677562013-11-17 15:52:551204 synthetic_trials->push_back(synthetic_trial_groups_[i].id);
1205 }
1206}
1207
dchengd99c42a2016-04-21 21:54:131208std::unique_ptr<MetricsLog> MetricsService::CreateLog(
1209 MetricsLog::LogType log_type) {
ricea85ec57952016-08-31 09:34:101210 return base::MakeUnique<MetricsLog>(state_manager_->client_id(), session_id_,
1211 log_type, client_, local_state_);
[email protected]09dee82d2014-05-22 14:00:531212}
1213
asvitkine88aa9332014-09-29 23:29:171214void MetricsService::RecordCurrentEnvironment(MetricsLog* log) {
manzagopa5d6688d2016-10-25 20:16:031215 DCHECK(client_);
asvitkine88aa9332014-09-29 23:29:171216 std::vector<variations::ActiveGroupId> synthetic_trials;
nasko7d4c2cb2015-11-26 01:29:351217 GetSyntheticFieldTrialsOlderThan(log->creation_time(), &synthetic_trials);
manzagopa5d6688d2016-10-25 20:16:031218 std::string serialized_environment = log->RecordEnvironment(
1219 metrics_providers_.get(), synthetic_trials, GetInstallDate(),
1220 GetMetricsReportingEnabledDate());
1221 client_->OnEnvironmentUpdate(&serialized_environment);
asvitkine88aa9332014-09-29 23:29:171222}
1223
[email protected]acc2ce5512014-05-22 18:29:131224void MetricsService::RecordCurrentHistograms() {
1225 DCHECK(log_manager_.current_log());
bcwhite9556e8172016-06-10 19:55:041226 SCOPED_UMA_HISTOGRAM_TIMER("UMA.MetricsService.RecordCurrentHistograms.Time");
bcwhite05dc0922016-06-03 04:59:441227
bcwhite34c6bbf2016-02-19 22:14:461228 // "true" to the begin() call indicates that StatisticsRecorder should include
1229 // histograms held in persistent storage.
bcwhite8373bd32016-07-13 02:49:111230 histogram_snapshot_manager_.PrepareDeltas(
bcwhite65e57d02016-05-13 14:39:401231 base::StatisticsRecorder::begin(true), base::StatisticsRecorder::end(),
1232 base::Histogram::kNoFlags, base::Histogram::kUmaTargetedHistogramFlag);
bcwhite34c6bbf2016-02-19 22:14:461233 for (MetricsProvider* provider : metrics_providers_)
1234 provider->RecordHistogramSnapshots(&histogram_snapshot_manager_);
[email protected]acc2ce5512014-05-22 18:29:131235}
1236
1237void MetricsService::RecordCurrentStabilityHistograms() {
1238 DCHECK(log_manager_.current_log());
bcwhite5cb99eb2016-02-01 21:07:561239 // "true" indicates that StatisticsRecorder should include histograms in
1240 // persistent storage.
bcwhite8373bd32016-07-13 02:49:111241 histogram_snapshot_manager_.PrepareDeltas(
bcwhite5cb99eb2016-02-01 21:07:561242 base::StatisticsRecorder::begin(true), base::StatisticsRecorder::end(),
[email protected]acc2ce5512014-05-22 18:29:131243 base::Histogram::kNoFlags, base::Histogram::kUmaStabilityHistogramFlag);
bcwhite65e57d02016-05-13 14:39:401244 for (MetricsProvider* provider : metrics_providers_)
1245 provider->RecordInitialHistogramSnapshots(&histogram_snapshot_manager_);
[email protected]acc2ce5512014-05-22 18:29:131246}
1247
holte6d341162016-12-19 21:42:421248void MetricsService::LogCleanShutdown(bool end_completed) {
holtea07de2062017-01-21 03:43:151249 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]c0c55e92011-09-10 18:47:301250 // Redundant setting to assure that we always reset this value at shutdown
1251 // (and that we don't use some alternate path, and not call LogCleanShutdown).
1252 clean_shutdown_status_ = CLEANLY_SHUTDOWN;
manzagop14aff5d2016-11-23 17:27:001253 client_->OnLogCleanShutdown();
erikwright65b58df2014-09-12 00:05:281254 clean_exit_beacon_.WriteBeaconValue(true);
holtea27eadf2017-01-26 01:58:591255 SetExecutionPhase(ExecutionPhase::SHUTDOWN_COMPLETE, local_state_);
holte6d341162016-12-19 21:42:421256 local_state_->SetBoolean(prefs::kStabilitySessionEndCompleted, end_completed);
initial.commit09911bf2008-07-26 23:55:291257}
asvitkinecbd420732014-08-26 22:15:401258
1259} // namespace metrics