1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 //------------------------------------------------------------------------------
6 // Description of the life cycle of a instance of MetricsService.
10 // A MetricsService instance is typically created at application startup. It is
11 // the central controller for the acquisition of log data, and the automatic
12 // 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,
16 // 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.
24 // Logs fall into one of two categories: "initial logs," and "ongoing logs."
25 // 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.
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)
39 // is 30 minutes. That time period starts when the first user action causes a
40 // logging event. This means that if there is no user action, there may be long
41 // periods without any (ongoing) log transmissions. Ongoing logs typically
42 // 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
48 // to the UMA server. The finalization also acquires the most recent number
49 // of page loads, along with any counts of renderer or plugin crashes.
51 // When the browser shuts down, there will typically be a fragment of an ongoing
52 // 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.
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.
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).
75 // With the above overview, we can now describe the state machine's various
76 // states, based on the State enum specified in the state_ member. Those states
79 // 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.
87 // In more detail, we have:
89 // INITIALIZED, // Constructor was called.
90 // The MS has been constructed, but has taken no actions to compose the
93 // INIT_TASK_SCHEDULED, // Waiting for deferred init tasks to finish.
94 // Typically about 30 seconds after startup, a task is sent to a second thread
95 // (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
100 // INIT_TASK_DONE, // Waiting for timer to send initial log.
101 // 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
103 // the deferred init task is dispatched.
105 // 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.
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.
122 // SENDING_OLD_LOGS, // Sending unsent logs from previous session.
123 // 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
129 // SENDING_CURRENT_LOGS, // Sending standard current logs as they accrue.
130 // Current logs are being accumulated. Typically every 20 minutes a log is
131 // closed and finalized for transmission, at the same time as a new log is
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.
138 // The one unusual case is when the user asks that we stop logging. When that
139 // happens, any staged (transmission in progress) log is persisted, and any log
140 // that is currently accumulating is also finalized and persisted. We then
141 // 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
146 // 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
151 // 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.
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
159 // side, but are not expected to be a significant problem.
162 //------------------------------------------------------------------------------
164 #include "chrome/browser/metrics/metrics_service.h"
168 #include "base/bind.h"
169 #include "base/callback.h"
170 #include "base/command_line.h"
171 #include "base/guid.h"
172 #include "base/md5.h"
173 #include "base/metrics/histogram.h"
174 #include "base/metrics/sparse_histogram.h"
175 #include "base/metrics/statistics_recorder.h"
176 #include "base/prefs/pref_registry_simple.h"
177 #include "base/prefs/pref_service.h"
178 #include "base/prefs/scoped_user_pref_update.h"
179 #include "base/rand_util.h"
180 #include "base/strings/string_number_conversions.h"
181 #include "base/strings/utf_string_conversions.h"
182 #include "base/threading/platform_thread.h"
183 #include "base/threading/thread.h"
184 #include "base/threading/thread_restrictions.h"
185 #include "base/tracked_objects.h"
186 #include "base/values.h"
187 #include "chrome/browser/browser_process.h"
188 #include "chrome/browser/chrome_notification_types.h"
189 #include "chrome/browser/io_thread.h"
190 #include "chrome/browser/memory_details.h"
191 #include "chrome/browser/metrics/compression_utils.h"
192 #include "chrome/browser/metrics/metrics_log.h"
193 #include "chrome/browser/metrics/metrics_log_serializer.h"
194 #include "chrome/browser/metrics/metrics_reporting_scheduler.h"
195 #include "chrome/browser/metrics/time_ticks_experiment_win.h"
196 #include "chrome/browser/metrics/tracking_synchronizer.h"
197 #include "chrome/common/metrics/variations/variations_util.h"
198 #include "chrome/browser/net/http_pipelining_compatibility_client.h"
199 #include "chrome/browser/net/network_stats.h"
200 #include "chrome/browser/omnibox/omnibox_log.h"
201 #include "chrome/browser/ui/browser_list.h"
202 #include "chrome/browser/ui/browser_otr_state.h"
203 #include "chrome/browser/ui/search/search_tab_helper.h"
204 #include "chrome/common/chrome_constants.h"
205 #include "chrome/common/chrome_result_codes.h"
206 #include "chrome/common/chrome_switches.h"
207 #include "chrome/common/crash_keys.h"
208 #include "chrome/common/metrics/caching_permuted_entropy_provider.h"
209 #include "chrome/common/metrics/metrics_log_manager.h"
210 #include "chrome/common/net/test_server_locations.h"
211 #include "chrome/common/pref_names.h"
212 #include "chrome/common/render_messages.h"
213 #include "components/variations/entropy_provider.h"
214 #include "components/variations/metrics_util.h"
215 #include "content/public/browser/child_process_data.h"
216 #include "content/public/browser/histogram_fetcher.h"
217 #include "content/public/browser/load_notification_details.h"
218 #include "content/public/browser/notification_service.h"
219 #include "content/public/browser/plugin_service.h"
220 #include "content/public/browser/render_process_host.h"
221 #include "content/public/browser/user_metrics.h"
222 #include "content/public/browser/web_contents.h"
223 #include "content/public/common/process_type.h"
224 #include "content/public/common/webplugininfo.h"
225 #include "extensions/browser/process_map.h"
226 #include "net/base/load_flags.h"
227 #include "net/url_request/url_fetcher.h"
229 // TODO(port): port browser_distribution.h.
230 #if !defined(OS_POSIX)
231 #include "chrome/installer/util/browser_distribution.h"
234 #if defined(OS_CHROMEOS)
235 #include "chrome/browser/chromeos/external_metrics.h"
236 #include "chromeos/system/statistics_provider.h"
240 #include <windows.h> // Needed for STATUS_* codes
241 #include "base/win/registry.h"
244 #if !defined(OS_ANDROID)
245 #include "chrome/browser/service_process/service_process_control.h"
249 using content::BrowserThread
;
250 using content::ChildProcessData
;
251 using content::LoadNotificationDetails
;
252 using content::PluginService
;
256 // Check to see that we're being called on only one thread.
257 bool IsSingleThreaded() {
258 static base::PlatformThreadId thread_id
= 0;
260 thread_id
= base::PlatformThread::CurrentId();
261 return base::PlatformThread::CurrentId() == thread_id
;
264 // The delay, in seconds, after starting recording before doing expensive
265 // initialization work.
266 #if defined(OS_ANDROID) || defined(OS_IOS)
267 // On mobile devices, a significant portion of sessions last less than a minute.
268 // Use a shorter timer on these platforms to avoid losing data.
269 // TODO(dfalcantara): To avoid delaying startup, tighten up initialization so
270 // that it occurs after the user gets their initial page.
271 const int kInitializationDelaySeconds
= 5;
273 const int kInitializationDelaySeconds
= 30;
276 // This specifies the amount of time to wait for all renderers to send their
278 const int kMaxHistogramGatheringWaitDuration
= 60000; // 60 seconds.
280 // The maximum number of events in a log uploaded to the UMA server.
281 const int kEventLimit
= 2400;
283 // If an upload fails, and the transmission was over this byte count, then we
284 // will discard the log, and not try to retransmit it. We also don't persist
285 // the log to the prefs for transmission during the next chrome session if this
286 // limit is exceeded.
287 const size_t kUploadLogAvoidRetransmitSize
= 50000;
289 // Interval, in minutes, between state saves.
290 const int kSaveStateIntervalMinutes
= 5;
292 enum ResponseStatus
{
295 BAD_REQUEST
, // Invalid syntax or log too large.
297 NUM_RESPONSE_STATUSES
300 ResponseStatus
ResponseCodeToStatus(int response_code
) {
301 switch (response_code
) {
306 case net::URLFetcher::RESPONSE_CODE_INVALID
:
309 return UNKNOWN_FAILURE
;
313 // The argument used to generate a non-identifying entropy source. We want no
314 // more than 13 bits of entropy, so use this max to return a number in the range
315 // [0, 7999] as the entropy source (12.97 bits of entropy).
316 const int kMaxLowEntropySize
= 8000;
318 // Default prefs value for prefs::kMetricsLowEntropySource to indicate that the
319 // value has not yet been set.
320 const int kLowEntropySourceNotSet
= -1;
322 // Generates a new non-identifying entropy source used to seed persistent
324 int GenerateLowEntropySource() {
325 return base::RandInt(0, kMaxLowEntropySize
- 1);
328 // Converts an exit code into something that can be inserted into our
329 // histograms (which expect non-negative numbers less than MAX_INT).
330 int MapCrashExitCodeForHistogram(int exit_code
) {
332 // Since |abs(STATUS_GUARD_PAGE_VIOLATION) == MAX_INT| it causes problems in
333 // histograms.cc. Solve this by remapping it to a smaller value, which
334 // hopefully doesn't conflict with other codes.
335 if (exit_code
== STATUS_GUARD_PAGE_VIOLATION
)
336 return 0x1FCF7EC3; // Randomly picked number.
339 return std::abs(exit_code
);
342 void MarkAppCleanShutdownAndCommit() {
343 PrefService
* pref
= g_browser_process
->local_state();
344 pref
->SetBoolean(prefs::kStabilityExitedCleanly
, true);
345 pref
->SetInteger(prefs::kStabilityExecutionPhase
,
346 MetricsService::SHUTDOWN_COMPLETE
);
347 // Start writing right away (write happens on a different thread).
348 pref
->CommitPendingWrite();
351 // Returns whether initial stability metrics should be sent in a separate log.
352 bool SendSeparateInitialStabilityLog() {
353 return base::FieldTrialList::FindFullName("UMAStability") == "SeparateLog";
359 SyntheticTrialGroup::SyntheticTrialGroup(uint32 trial
,
361 base::TimeTicks start
)
362 : start_time(start
) {
367 SyntheticTrialGroup::~SyntheticTrialGroup() {
371 MetricsService::ShutdownCleanliness
MetricsService::clean_shutdown_status_
=
372 MetricsService::CLEANLY_SHUTDOWN
;
374 MetricsService::ExecutionPhase
MetricsService::execution_phase_
=
375 MetricsService::UNINITIALIZED_PHASE
;
377 // This is used to quickly log stats from child process related notifications in
378 // MetricsService::child_stats_buffer_. The buffer's contents are transferred
379 // out when Local State is periodically saved. The information is then
380 // reported to the UMA server on next launch.
381 struct MetricsService::ChildProcessStats
{
383 explicit ChildProcessStats(int process_type
)
384 : process_launches(0),
388 process_type(process_type
) {}
390 // This constructor is only used by the map to return some default value for
391 // an index for which no value has been assigned.
393 : process_launches(0),
397 process_type(content::PROCESS_TYPE_UNKNOWN
) {}
399 // The number of times that the given child process has been launched
400 int process_launches
;
402 // The number of times that the given child process has crashed
405 // The number of instances of this child process that have been created.
406 // An instance is a DOM object rendered by this child process during a page
410 // The number of times there was an error loading an instance of this child
417 // Handles asynchronous fetching of memory details.
418 // Will run the provided task after finished.
419 class MetricsMemoryDetails
: public MemoryDetails
{
421 explicit MetricsMemoryDetails(const base::Closure
& callback
)
422 : callback_(callback
) {}
424 virtual void OnDetailsAvailable() OVERRIDE
{
425 base::MessageLoop::current()->PostTask(FROM_HERE
, callback_
);
429 virtual ~MetricsMemoryDetails() {}
431 base::Closure callback_
;
432 DISALLOW_COPY_AND_ASSIGN(MetricsMemoryDetails
);
436 void MetricsService::RegisterPrefs(PrefRegistrySimple
* registry
) {
437 DCHECK(IsSingleThreaded());
438 registry
->RegisterStringPref(prefs::kMetricsClientID
, std::string());
439 registry
->RegisterIntegerPref(prefs::kMetricsLowEntropySource
,
440 kLowEntropySourceNotSet
);
441 registry
->RegisterInt64Pref(prefs::kMetricsClientIDTimestamp
, 0);
442 registry
->RegisterInt64Pref(prefs::kStabilityLaunchTimeSec
, 0);
443 registry
->RegisterInt64Pref(prefs::kStabilityLastTimestampSec
, 0);
444 registry
->RegisterStringPref(prefs::kStabilityStatsVersion
, std::string());
445 registry
->RegisterInt64Pref(prefs::kStabilityStatsBuildTime
, 0);
446 registry
->RegisterBooleanPref(prefs::kStabilityExitedCleanly
, true);
447 registry
->RegisterIntegerPref(prefs::kStabilityExecutionPhase
,
448 UNINITIALIZED_PHASE
);
449 registry
->RegisterBooleanPref(prefs::kStabilitySessionEndCompleted
, true);
450 registry
->RegisterIntegerPref(prefs::kMetricsSessionID
, -1);
451 registry
->RegisterIntegerPref(prefs::kStabilityLaunchCount
, 0);
452 registry
->RegisterIntegerPref(prefs::kStabilityCrashCount
, 0);
453 registry
->RegisterIntegerPref(prefs::kStabilityIncompleteSessionEndCount
, 0);
454 registry
->RegisterIntegerPref(prefs::kStabilityPageLoadCount
, 0);
455 registry
->RegisterIntegerPref(prefs::kStabilityRendererCrashCount
, 0);
456 registry
->RegisterIntegerPref(prefs::kStabilityExtensionRendererCrashCount
,
458 registry
->RegisterIntegerPref(prefs::kStabilityRendererHangCount
, 0);
459 registry
->RegisterIntegerPref(prefs::kStabilityChildProcessCrashCount
, 0);
460 registry
->RegisterIntegerPref(prefs::kStabilityBreakpadRegistrationFail
, 0);
461 registry
->RegisterIntegerPref(prefs::kStabilityBreakpadRegistrationSuccess
,
463 registry
->RegisterIntegerPref(prefs::kStabilityDebuggerPresent
, 0);
464 registry
->RegisterIntegerPref(prefs::kStabilityDebuggerNotPresent
, 0);
465 #if defined(OS_CHROMEOS)
466 registry
->RegisterIntegerPref(prefs::kStabilityOtherUserCrashCount
, 0);
467 registry
->RegisterIntegerPref(prefs::kStabilityKernelCrashCount
, 0);
468 registry
->RegisterIntegerPref(prefs::kStabilitySystemUncleanShutdownCount
, 0);
469 #endif // OS_CHROMEOS
471 registry
->RegisterStringPref(prefs::kStabilitySavedSystemProfile
,
473 registry
->RegisterStringPref(prefs::kStabilitySavedSystemProfileHash
,
476 registry
->RegisterListPref(prefs::kMetricsInitialLogs
);
477 registry
->RegisterListPref(prefs::kMetricsOngoingLogs
);
479 registry
->RegisterInt64Pref(prefs::kInstallDate
, 0);
480 registry
->RegisterInt64Pref(prefs::kUninstallMetricsPageLoadCount
, 0);
481 registry
->RegisterInt64Pref(prefs::kUninstallLaunchCount
, 0);
482 registry
->RegisterInt64Pref(prefs::kUninstallMetricsUptimeSec
, 0);
483 registry
->RegisterInt64Pref(prefs::kUninstallLastLaunchTimeSec
, 0);
484 registry
->RegisterInt64Pref(prefs::kUninstallLastObservedRunTimeSec
, 0);
488 void MetricsService::DiscardOldStabilityStats(PrefService
* local_state
) {
489 local_state
->SetBoolean(prefs::kStabilityExitedCleanly
, true);
490 local_state
->SetInteger(prefs::kStabilityExecutionPhase
, UNINITIALIZED_PHASE
);
491 local_state
->SetBoolean(prefs::kStabilitySessionEndCompleted
, true);
493 local_state
->SetInteger(prefs::kStabilityIncompleteSessionEndCount
, 0);
494 local_state
->SetInteger(prefs::kStabilityBreakpadRegistrationSuccess
, 0);
495 local_state
->SetInteger(prefs::kStabilityBreakpadRegistrationFail
, 0);
496 local_state
->SetInteger(prefs::kStabilityDebuggerPresent
, 0);
497 local_state
->SetInteger(prefs::kStabilityDebuggerNotPresent
, 0);
499 local_state
->SetInteger(prefs::kStabilityLaunchCount
, 0);
500 local_state
->SetInteger(prefs::kStabilityCrashCount
, 0);
502 local_state
->SetInteger(prefs::kStabilityPageLoadCount
, 0);
503 local_state
->SetInteger(prefs::kStabilityRendererCrashCount
, 0);
504 local_state
->SetInteger(prefs::kStabilityRendererHangCount
, 0);
506 local_state
->SetInt64(prefs::kStabilityLaunchTimeSec
, 0);
507 local_state
->SetInt64(prefs::kStabilityLastTimestampSec
, 0);
509 local_state
->ClearPref(prefs::kStabilityPluginStats
);
511 local_state
->ClearPref(prefs::kMetricsInitialLogs
);
512 local_state
->ClearPref(prefs::kMetricsOngoingLogs
);
515 MetricsService::MetricsService()
516 : recording_active_(false),
517 reporting_active_(false),
518 test_mode_active_(false),
520 has_initial_stability_log_(false),
521 low_entropy_source_(kLowEntropySourceNotSet
),
522 idle_since_last_transmission_(false),
525 self_ptr_factory_(this),
526 state_saver_factory_(this),
527 waiting_for_asynchronous_reporting_step_(false),
528 num_async_histogram_fetches_in_progress_(0),
529 entropy_source_returned_(LAST_ENTROPY_NONE
) {
530 DCHECK(IsSingleThreaded());
532 log_manager_
.set_log_serializer(new MetricsLogSerializer
);
533 log_manager_
.set_max_ongoing_log_store_size(kUploadLogAvoidRetransmitSize
);
535 BrowserChildProcessObserver::Add(this);
538 MetricsService::~MetricsService() {
541 BrowserChildProcessObserver::Remove(this);
544 void MetricsService::InitializeMetricsRecordingState(
545 ReportingState reporting_state
) {
546 InitializeMetricsState(reporting_state
);
548 base::Closure callback
= base::Bind(&MetricsService::StartScheduledUpload
,
549 self_ptr_factory_
.GetWeakPtr());
550 scheduler_
.reset(new MetricsReportingScheduler(callback
));
553 void MetricsService::Start() {
554 HandleIdleSinceLastTransmission(false);
559 void MetricsService::StartRecordingForTests() {
560 test_mode_active_
= true;
565 void MetricsService::Stop() {
566 HandleIdleSinceLastTransmission(false);
571 void MetricsService::EnableReporting() {
572 if (reporting_active_
)
574 reporting_active_
= true;
575 StartSchedulerIfNecessary();
578 void MetricsService::DisableReporting() {
579 reporting_active_
= false;
582 std::string
MetricsService::GetClientId() {
586 scoped_ptr
<const base::FieldTrial::EntropyProvider
>
587 MetricsService::CreateEntropyProvider(ReportingState reporting_state
) {
588 // For metrics reporting-enabled users, we combine the client ID and low
589 // entropy source to get the final entropy source. Otherwise, only use the low
591 // This has two useful properties:
592 // 1) It makes the entropy source less identifiable for parties that do not
593 // know the low entropy source.
594 // 2) It makes the final entropy source resettable.
595 const int low_entropy_source_value
= GetLowEntropySource();
596 UMA_HISTOGRAM_SPARSE_SLOWLY("UMA.LowEntropySourceValue",
597 low_entropy_source_value
);
598 if (reporting_state
== REPORTING_ENABLED
) {
599 if (entropy_source_returned_
== LAST_ENTROPY_NONE
)
600 entropy_source_returned_
= LAST_ENTROPY_HIGH
;
601 DCHECK_EQ(LAST_ENTROPY_HIGH
, entropy_source_returned_
);
602 const std::string high_entropy_source
=
603 client_id_
+ base::IntToString(low_entropy_source_value
);
604 return scoped_ptr
<const base::FieldTrial::EntropyProvider
>(
605 new metrics::SHA1EntropyProvider(high_entropy_source
));
608 if (entropy_source_returned_
== LAST_ENTROPY_NONE
)
609 entropy_source_returned_
= LAST_ENTROPY_LOW
;
610 DCHECK_EQ(LAST_ENTROPY_LOW
, entropy_source_returned_
);
612 #if defined(OS_ANDROID) || defined(OS_IOS)
613 return scoped_ptr
<const base::FieldTrial::EntropyProvider
>(
614 new metrics::CachingPermutedEntropyProvider(
615 g_browser_process
->local_state(),
616 low_entropy_source_value
,
617 kMaxLowEntropySize
));
619 return scoped_ptr
<const base::FieldTrial::EntropyProvider
>(
620 new metrics::PermutedEntropyProvider(low_entropy_source_value
,
621 kMaxLowEntropySize
));
625 void MetricsService::ForceClientIdCreation() {
626 if (!client_id_
.empty())
628 PrefService
* pref
= g_browser_process
->local_state();
629 client_id_
= pref
->GetString(prefs::kMetricsClientID
);
630 if (!client_id_
.empty())
633 client_id_
= GenerateClientID();
634 pref
->SetString(prefs::kMetricsClientID
, client_id_
);
636 // Might as well make a note of how long this ID has existed
637 pref
->SetString(prefs::kMetricsClientIDTimestamp
,
638 base::Int64ToString(Time::Now().ToTimeT()));
641 void MetricsService::EnableRecording() {
642 DCHECK(IsSingleThreaded());
644 if (recording_active_
)
646 recording_active_
= true;
648 ForceClientIdCreation();
649 crash_keys::SetClientID(client_id_
);
650 if (!log_manager_
.current_log())
653 SetUpNotifications(®istrar_
, this);
654 base::RemoveActionCallback(action_callback_
);
655 action_callback_
= base::Bind(&MetricsService::OnUserAction
,
656 base::Unretained(this));
657 base::AddActionCallback(action_callback_
);
660 void MetricsService::DisableRecording() {
661 DCHECK(IsSingleThreaded());
663 if (!recording_active_
)
665 recording_active_
= false;
667 base::RemoveActionCallback(action_callback_
);
668 registrar_
.RemoveAll();
669 PushPendingLogsToPersistentStorage();
670 DCHECK(!log_manager_
.has_staged_log());
673 bool MetricsService::recording_active() const {
674 DCHECK(IsSingleThreaded());
675 return recording_active_
;
678 bool MetricsService::reporting_active() const {
679 DCHECK(IsSingleThreaded());
680 return reporting_active_
;
684 void MetricsService::SetUpNotifications(
685 content::NotificationRegistrar
* registrar
,
686 content::NotificationObserver
* observer
) {
687 registrar
->Add(observer
, chrome::NOTIFICATION_BROWSER_OPENED
,
688 content::NotificationService::AllBrowserContextsAndSources());
689 registrar
->Add(observer
, chrome::NOTIFICATION_BROWSER_CLOSED
,
690 content::NotificationService::AllSources());
691 registrar
->Add(observer
, chrome::NOTIFICATION_TAB_PARENTED
,
692 content::NotificationService::AllSources());
693 registrar
->Add(observer
, chrome::NOTIFICATION_TAB_CLOSING
,
694 content::NotificationService::AllSources());
695 registrar
->Add(observer
, content::NOTIFICATION_LOAD_START
,
696 content::NotificationService::AllSources());
697 registrar
->Add(observer
, content::NOTIFICATION_LOAD_STOP
,
698 content::NotificationService::AllSources());
699 registrar
->Add(observer
, content::NOTIFICATION_RENDERER_PROCESS_CLOSED
,
700 content::NotificationService::AllSources());
701 registrar
->Add(observer
, content::NOTIFICATION_RENDER_WIDGET_HOST_HANG
,
702 content::NotificationService::AllSources());
703 registrar
->Add(observer
, chrome::NOTIFICATION_OMNIBOX_OPENED_URL
,
704 content::NotificationService::AllSources());
707 void MetricsService::BrowserChildProcessHostConnected(
708 const content::ChildProcessData
& data
) {
709 GetChildProcessStats(data
).process_launches
++;
712 void MetricsService::BrowserChildProcessCrashed(
713 const content::ChildProcessData
& data
) {
714 GetChildProcessStats(data
).process_crashes
++;
715 // Exclude plugin crashes from the count below because we report them via
716 // a separate UMA metric.
717 if (!IsPluginProcess(data
.process_type
))
718 IncrementPrefValue(prefs::kStabilityChildProcessCrashCount
);
721 void MetricsService::BrowserChildProcessInstanceCreated(
722 const content::ChildProcessData
& data
) {
723 GetChildProcessStats(data
).instances
++;
726 void MetricsService::Observe(int type
,
727 const content::NotificationSource
& source
,
728 const content::NotificationDetails
& details
) {
729 DCHECK(log_manager_
.current_log());
730 DCHECK(IsSingleThreaded());
732 if (!CanLogNotification())
736 case chrome::NOTIFICATION_BROWSER_OPENED
:
737 case chrome::NOTIFICATION_BROWSER_CLOSED
:
738 case chrome::NOTIFICATION_TAB_PARENTED
:
739 case chrome::NOTIFICATION_TAB_CLOSING
:
740 case content::NOTIFICATION_LOAD_STOP
:
741 // These notifications are currently used only to break out of idle mode.
744 case content::NOTIFICATION_LOAD_START
: {
745 content::NavigationController
* controller
=
746 content::Source
<content::NavigationController
>(source
).ptr();
747 content::WebContents
* web_contents
= controller
->GetWebContents();
748 LogLoadStarted(web_contents
);
752 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED
: {
753 content::RenderProcessHost::RendererClosedDetails
* process_details
=
755 content::RenderProcessHost::RendererClosedDetails
>(
757 content::RenderProcessHost
* host
=
758 content::Source
<content::RenderProcessHost
>(source
).ptr();
760 host
, process_details
->status
, process_details
->exit_code
);
764 case content::NOTIFICATION_RENDER_WIDGET_HOST_HANG
:
768 case chrome::NOTIFICATION_OMNIBOX_OPENED_URL
: {
769 MetricsLog
* current_log
=
770 static_cast<MetricsLog
*>(log_manager_
.current_log());
772 current_log
->RecordOmniboxOpenedURL(
773 *content::Details
<OmniboxLog
>(details
).ptr());
782 HandleIdleSinceLastTransmission(false);
785 void MetricsService::HandleIdleSinceLastTransmission(bool in_idle
) {
786 // If there wasn't a lot of action, maybe the computer was asleep, in which
787 // case, the log transmissions should have stopped. Here we start them up
789 if (!in_idle
&& idle_since_last_transmission_
)
790 StartSchedulerIfNecessary();
791 idle_since_last_transmission_
= in_idle
;
794 void MetricsService::RecordStartOfSessionEnd() {
796 RecordBooleanPrefValue(prefs::kStabilitySessionEndCompleted
, false);
799 void MetricsService::RecordCompletedSessionEnd() {
801 RecordBooleanPrefValue(prefs::kStabilitySessionEndCompleted
, true);
804 #if defined(OS_ANDROID) || defined(OS_IOS)
805 void MetricsService::OnAppEnterBackground() {
808 MarkAppCleanShutdownAndCommit();
810 // At this point, there's no way of knowing when the process will be
811 // killed, so this has to be treated similar to a shutdown, closing and
812 // persisting all logs. Unlinke a shutdown, the state is primed to be ready
813 // to continue logging and uploading if the process does return.
814 if (recording_active() && state_
>= SENDING_INITIAL_STABILITY_LOG
) {
815 PushPendingLogsToPersistentStorage();
816 // Persisting logs closes the current log, so start recording a new log
817 // immediately to capture any background work that might be done before the
818 // process is killed.
823 void MetricsService::OnAppEnterForeground() {
824 PrefService
* pref
= g_browser_process
->local_state();
825 pref
->SetBoolean(prefs::kStabilityExitedCleanly
, false);
827 StartSchedulerIfNecessary();
830 void MetricsService::LogNeedForCleanShutdown() {
831 PrefService
* pref
= g_browser_process
->local_state();
832 pref
->SetBoolean(prefs::kStabilityExitedCleanly
, false);
833 // Redundant setting to be sure we call for a clean shutdown.
834 clean_shutdown_status_
= NEED_TO_SHUTDOWN
;
836 #endif // defined(OS_ANDROID) || defined(OS_IOS)
839 void MetricsService::SetExecutionPhase(ExecutionPhase execution_phase
) {
840 execution_phase_
= execution_phase
;
841 PrefService
* pref
= g_browser_process
->local_state();
842 pref
->SetInteger(prefs::kStabilityExecutionPhase
, execution_phase_
);
845 void MetricsService::RecordBreakpadRegistration(bool success
) {
847 IncrementPrefValue(prefs::kStabilityBreakpadRegistrationFail
);
849 IncrementPrefValue(prefs::kStabilityBreakpadRegistrationSuccess
);
852 void MetricsService::RecordBreakpadHasDebugger(bool has_debugger
) {
854 IncrementPrefValue(prefs::kStabilityDebuggerNotPresent
);
856 IncrementPrefValue(prefs::kStabilityDebuggerPresent
);
860 void MetricsService::CountBrowserCrashDumpAttempts() {
861 // Open the registry key for iteration.
862 base::win::RegKey regkey
;
863 if (regkey
.Open(HKEY_CURRENT_USER
,
864 chrome::kBrowserCrashDumpAttemptsRegistryPath
,
865 KEY_ALL_ACCESS
) != ERROR_SUCCESS
) {
869 // The values we're interested in counting are all prefixed with the version.
870 base::string16
chrome_version(base::ASCIIToUTF16(chrome::kChromeVersion
));
872 // Track a list of values to delete. We don't modify the registry key while
873 // we're iterating over its values.
874 typedef std::vector
<base::string16
> StringVector
;
875 StringVector to_delete
;
877 // Iterate over the values in the key counting dumps with and without crashes.
878 // We directly walk the values instead of using RegistryValueIterator in order
879 // to read all of the values as DWORDS instead of strings.
882 int dumps_with_crash
= 0;
883 int dumps_with_no_crash
= 0;
884 for (int i
= regkey
.GetValueCount() - 1; i
>= 0; --i
) {
885 if (regkey
.GetValueNameAt(i
, &name
) == ERROR_SUCCESS
&&
886 StartsWith(name
, chrome_version
, false) &&
887 regkey
.ReadValueDW(name
.c_str(), &value
) == ERROR_SUCCESS
) {
888 to_delete
.push_back(name
);
890 ++dumps_with_no_crash
;
896 // Delete the registry keys we've just counted.
897 for (StringVector::iterator i
= to_delete
.begin(); i
!= to_delete
.end(); ++i
)
898 regkey
.DeleteValue(i
->c_str());
900 // Capture the histogram samples.
901 if (dumps_with_crash
!= 0)
902 UMA_HISTOGRAM_COUNTS("Chrome.BrowserDumpsWithCrash", dumps_with_crash
);
903 if (dumps_with_no_crash
!= 0)
904 UMA_HISTOGRAM_COUNTS("Chrome.BrowserDumpsWithNoCrash", dumps_with_no_crash
);
905 int total_dumps
= dumps_with_crash
+ dumps_with_no_crash
;
906 if (total_dumps
!= 0)
907 UMA_HISTOGRAM_COUNTS("Chrome.BrowserCrashDumpAttempts", total_dumps
);
909 #endif // defined(OS_WIN)
911 //------------------------------------------------------------------------------
913 //------------------------------------------------------------------------------
916 //------------------------------------------------------------------------------
917 // Initialization methods
919 void MetricsService::InitializeMetricsState(ReportingState reporting_state
) {
920 #if defined(OS_POSIX)
921 network_stats_server_
= chrome_common_net::kEchoTestServerLocation
;
922 http_pipelining_test_server_
= chrome_common_net::kPipelineTestServerBaseUrl
;
924 BrowserDistribution
* dist
= BrowserDistribution::GetDistribution();
925 network_stats_server_
= dist
->GetNetworkStatsServer();
926 http_pipelining_test_server_
= dist
->GetHttpPipeliningTestServer();
929 PrefService
* pref
= g_browser_process
->local_state();
932 // TODO(asvitkine): Kill this logic when SendSeparateInitialStabilityLog() is
933 // is made the default behavior.
934 if ((pref
->GetInt64(prefs::kStabilityStatsBuildTime
)
935 != MetricsLog::GetBuildTime()) ||
936 (pref
->GetString(prefs::kStabilityStatsVersion
)
937 != MetricsLog::GetVersionString())) {
938 // This is a new version, so we don't want to confuse the stats about the
939 // old version with info that we upload.
940 DiscardOldStabilityStats(pref
);
941 pref
->SetString(prefs::kStabilityStatsVersion
,
942 MetricsLog::GetVersionString());
943 pref
->SetInt64(prefs::kStabilityStatsBuildTime
,
944 MetricsLog::GetBuildTime());
947 session_id_
= pref
->GetInteger(prefs::kMetricsSessionID
);
949 if (!pref
->GetBoolean(prefs::kStabilityExitedCleanly
)) {
950 IncrementPrefValue(prefs::kStabilityCrashCount
);
951 // Reset flag, and wait until we call LogNeedForCleanShutdown() before
953 pref
->SetBoolean(prefs::kStabilityExitedCleanly
, true);
955 // TODO(rtenneti): On windows, consider saving/getting execution_phase from
957 int execution_phase
= pref
->GetInteger(prefs::kStabilityExecutionPhase
);
958 UMA_HISTOGRAM_SPARSE_SLOWLY("Chrome.Browser.CrashedExecutionPhase",
961 // If the previous session didn't exit cleanly, then prepare an initial
962 // stability log if UMA is enabled.
963 bool reporting_will_be_enabled
= (reporting_state
== REPORTING_ENABLED
);
964 if (reporting_will_be_enabled
&& SendSeparateInitialStabilityLog())
965 PrepareInitialStabilityLog();
968 // Update session ID.
970 pref
->SetInteger(prefs::kMetricsSessionID
, session_id_
);
972 // Stability bookkeeping
973 IncrementPrefValue(prefs::kStabilityLaunchCount
);
975 DCHECK_EQ(UNINITIALIZED_PHASE
, execution_phase_
);
976 SetExecutionPhase(START_METRICS_RECORDING
);
979 CountBrowserCrashDumpAttempts();
980 #endif // defined(OS_WIN)
982 if (!pref
->GetBoolean(prefs::kStabilitySessionEndCompleted
)) {
983 IncrementPrefValue(prefs::kStabilityIncompleteSessionEndCount
);
984 // This is marked false when we get a WM_ENDSESSION.
985 pref
->SetBoolean(prefs::kStabilitySessionEndCompleted
, true);
988 // Initialize uptime counters.
989 const base::TimeDelta startup_uptime
= GetIncrementalUptime(pref
);
990 DCHECK_EQ(0, startup_uptime
.InMicroseconds());
991 // For backwards compatibility, leave this intact in case Omaha is checking
992 // them. prefs::kStabilityLastTimestampSec may also be useless now.
993 // TODO(jar): Delete these if they have no uses.
994 pref
->SetInt64(prefs::kStabilityLaunchTimeSec
, Time::Now().ToTimeT());
996 // Bookkeeping for the uninstall metrics.
997 IncrementLongPrefsValue(prefs::kUninstallLaunchCount
);
999 // Get stats on use of command line.
1000 const CommandLine
* command_line(CommandLine::ForCurrentProcess());
1001 size_t common_commands
= 0;
1002 if (command_line
->HasSwitch(switches::kUserDataDir
)) {
1004 UMA_HISTOGRAM_COUNTS_100("Chrome.CommandLineDatDirCount", 1);
1007 if (command_line
->HasSwitch(switches::kApp
)) {
1009 UMA_HISTOGRAM_COUNTS_100("Chrome.CommandLineAppModeCount", 1);
1012 size_t switch_count
= command_line
->GetSwitches().size();
1013 UMA_HISTOGRAM_COUNTS_100("Chrome.CommandLineFlagCount", switch_count
);
1014 UMA_HISTOGRAM_COUNTS_100("Chrome.CommandLineUncommonFlagCount",
1015 switch_count
- common_commands
);
1017 // Kick off the process of saving the state (so the uptime numbers keep
1018 // getting updated) every n minutes.
1019 ScheduleNextStateSave();
1023 void MetricsService::InitTaskGetHardwareClass(
1024 base::WeakPtr
<MetricsService
> self
,
1025 base::MessageLoopProxy
* target_loop
) {
1026 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
1028 std::string hardware_class
;
1029 #if defined(OS_CHROMEOS)
1030 chromeos::system::StatisticsProvider::GetInstance()->GetMachineStatistic(
1031 "hardware_class", &hardware_class
);
1032 #endif // OS_CHROMEOS
1034 target_loop
->PostTask(FROM_HERE
,
1035 base::Bind(&MetricsService::OnInitTaskGotHardwareClass
,
1036 self
, hardware_class
));
1039 void MetricsService::OnInitTaskGotHardwareClass(
1040 const std::string
& hardware_class
) {
1041 DCHECK_EQ(INIT_TASK_SCHEDULED
, state_
);
1042 hardware_class_
= hardware_class
;
1044 #if defined(ENABLE_PLUGINS)
1045 // Start the next part of the init task: loading plugin information.
1046 PluginService::GetInstance()->GetPlugins(
1047 base::Bind(&MetricsService::OnInitTaskGotPluginInfo
,
1048 self_ptr_factory_
.GetWeakPtr()));
1050 std::vector
<content::WebPluginInfo
> plugin_list_empty
;
1051 OnInitTaskGotPluginInfo(plugin_list_empty
);
1052 #endif // defined(ENABLE_PLUGINS)
1055 void MetricsService::OnInitTaskGotPluginInfo(
1056 const std::vector
<content::WebPluginInfo
>& plugins
) {
1057 DCHECK_EQ(INIT_TASK_SCHEDULED
, state_
);
1060 // Schedules a task on a blocking pool thread to gather Google Update
1061 // statistics (requires Registry reads).
1062 BrowserThread::PostBlockingPoolTask(
1064 base::Bind(&MetricsService::InitTaskGetGoogleUpdateData
,
1065 self_ptr_factory_
.GetWeakPtr(),
1066 base::MessageLoop::current()->message_loop_proxy()));
1070 void MetricsService::InitTaskGetGoogleUpdateData(
1071 base::WeakPtr
<MetricsService
> self
,
1072 base::MessageLoopProxy
* target_loop
) {
1073 GoogleUpdateMetrics google_update_metrics
;
1075 #if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
1076 const bool system_install
= GoogleUpdateSettings::IsSystemInstall();
1078 google_update_metrics
.is_system_install
= system_install
;
1079 google_update_metrics
.last_started_au
=
1080 GoogleUpdateSettings::GetGoogleUpdateLastStartedAU(system_install
);
1081 google_update_metrics
.last_checked
=
1082 GoogleUpdateSettings::GetGoogleUpdateLastChecked(system_install
);
1083 GoogleUpdateSettings::GetUpdateDetailForGoogleUpdate(
1085 &google_update_metrics
.google_update_data
);
1086 GoogleUpdateSettings::GetUpdateDetail(
1088 &google_update_metrics
.product_data
);
1089 #endif // defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
1091 target_loop
->PostTask(FROM_HERE
,
1092 base::Bind(&MetricsService::OnInitTaskGotGoogleUpdateData
,
1093 self
, google_update_metrics
));
1096 void MetricsService::OnInitTaskGotGoogleUpdateData(
1097 const GoogleUpdateMetrics
& google_update_metrics
) {
1098 DCHECK_EQ(INIT_TASK_SCHEDULED
, state_
);
1100 google_update_metrics_
= google_update_metrics
;
1102 // Start the next part of the init task: fetching performance data. This will
1103 // call into |FinishedReceivingProfilerData()| when the task completes.
1104 chrome_browser_metrics::TrackingSynchronizer::FetchProfilerDataAsynchronously(
1105 self_ptr_factory_
.GetWeakPtr());
1108 void MetricsService::OnUserAction(const std::string
& action
) {
1109 if (!CanLogNotification())
1112 log_manager_
.current_log()->RecordUserAction(action
.c_str());
1113 HandleIdleSinceLastTransmission(false);
1116 void MetricsService::ReceivedProfilerData(
1117 const tracked_objects::ProcessDataSnapshot
& process_data
,
1119 DCHECK_EQ(INIT_TASK_SCHEDULED
, state_
);
1121 // Upon the first callback, create the initial log so that we can immediately
1122 // save the profiler data.
1123 if (!initial_metrics_log_
.get())
1124 initial_metrics_log_
.reset(new MetricsLog(client_id_
, session_id_
));
1126 initial_metrics_log_
->RecordProfilerData(process_data
, process_type
);
1129 void MetricsService::FinishedReceivingProfilerData() {
1130 DCHECK_EQ(INIT_TASK_SCHEDULED
, state_
);
1131 state_
= INIT_TASK_DONE
;
1132 scheduler_
->InitTaskComplete();
1135 base::TimeDelta
MetricsService::GetIncrementalUptime(PrefService
* pref
) {
1136 base::TimeTicks now
= base::TimeTicks::Now();
1137 // If this is the first call, init |last_updated_time_|.
1138 if (last_updated_time_
.is_null())
1139 last_updated_time_
= now
;
1140 const base::TimeDelta incremental_time
= now
- last_updated_time_
;
1141 last_updated_time_
= now
;
1143 const int64 incremental_time_secs
= incremental_time
.InSeconds();
1144 if (incremental_time_secs
> 0) {
1145 int64 metrics_uptime
= pref
->GetInt64(prefs::kUninstallMetricsUptimeSec
);
1146 metrics_uptime
+= incremental_time_secs
;
1147 pref
->SetInt64(prefs::kUninstallMetricsUptimeSec
, metrics_uptime
);
1150 return incremental_time
;
1153 int MetricsService::GetLowEntropySource() {
1154 // Note that the default value for the low entropy source and the default pref
1155 // value are both kLowEntropySourceNotSet, which is used to identify if the
1156 // value has been set or not.
1157 if (low_entropy_source_
!= kLowEntropySourceNotSet
)
1158 return low_entropy_source_
;
1160 PrefService
* local_state
= g_browser_process
->local_state();
1161 const CommandLine
* command_line(CommandLine::ForCurrentProcess());
1162 // Only try to load the value from prefs if the user did not request a reset.
1163 // Otherwise, skip to generating a new value.
1164 if (!command_line
->HasSwitch(switches::kResetVariationState
)) {
1165 int value
= local_state
->GetInteger(prefs::kMetricsLowEntropySource
);
1166 // Old versions of the code would generate values in the range of [1, 8192],
1167 // before the range was switched to [0, 8191] and then to [0, 7999]. Map
1168 // 8192 to 0, so that the 0th bucket remains uniform, while re-generating
1169 // the low entropy source for old values in the [8000, 8191] range.
1172 // If the value is outside the [0, kMaxLowEntropySize) range, re-generate
1174 if (value
>= 0 && value
< kMaxLowEntropySize
) {
1175 low_entropy_source_
= value
;
1176 UMA_HISTOGRAM_BOOLEAN("UMA.GeneratedLowEntropySource", false);
1177 return low_entropy_source_
;
1181 UMA_HISTOGRAM_BOOLEAN("UMA.GeneratedLowEntropySource", true);
1182 low_entropy_source_
= GenerateLowEntropySource();
1183 local_state
->SetInteger(prefs::kMetricsLowEntropySource
, low_entropy_source_
);
1184 metrics::CachingPermutedEntropyProvider::ClearCache(local_state
);
1186 return low_entropy_source_
;
1190 std::string
MetricsService::GenerateClientID() {
1191 return base::GenerateGUID();
1194 //------------------------------------------------------------------------------
1195 // State save methods
1197 void MetricsService::ScheduleNextStateSave() {
1198 state_saver_factory_
.InvalidateWeakPtrs();
1200 base::MessageLoop::current()->PostDelayedTask(FROM_HERE
,
1201 base::Bind(&MetricsService::SaveLocalState
,
1202 state_saver_factory_
.GetWeakPtr()),
1203 base::TimeDelta::FromMinutes(kSaveStateIntervalMinutes
));
1206 void MetricsService::SaveLocalState() {
1207 PrefService
* pref
= g_browser_process
->local_state();
1213 RecordCurrentState(pref
);
1215 // TODO(jar):110021 Does this run down the batteries????
1216 ScheduleNextStateSave();
1220 //------------------------------------------------------------------------------
1221 // Recording control methods
1223 void MetricsService::OpenNewLog() {
1224 DCHECK(!log_manager_
.current_log());
1226 log_manager_
.BeginLoggingWithLog(new MetricsLog(client_id_
, session_id_
),
1227 MetricsLog::ONGOING_LOG
);
1228 if (state_
== INITIALIZED
) {
1229 // We only need to schedule that run once.
1230 state_
= INIT_TASK_SCHEDULED
;
1232 // Schedules a task on the file thread for execution of slower
1233 // initialization steps (such as plugin list generation) necessary
1234 // for sending the initial log. This avoids blocking the main UI
1236 BrowserThread::PostDelayedTask(
1237 BrowserThread::FILE,
1239 base::Bind(&MetricsService::InitTaskGetHardwareClass
,
1240 self_ptr_factory_
.GetWeakPtr(),
1241 base::MessageLoop::current()->message_loop_proxy()),
1242 base::TimeDelta::FromSeconds(kInitializationDelaySeconds
));
1246 void MetricsService::CloseCurrentLog() {
1247 if (!log_manager_
.current_log())
1250 // TODO(jar): Integrate bounds on log recording more consistently, so that we
1251 // can stop recording logs that are too big much sooner.
1252 if (log_manager_
.current_log()->num_events() > kEventLimit
) {
1253 UMA_HISTOGRAM_COUNTS("UMA.Discarded Log Events",
1254 log_manager_
.current_log()->num_events());
1255 log_manager_
.DiscardCurrentLog();
1256 OpenNewLog(); // Start trivial log to hold our histograms.
1259 // Adds to ongoing logs.
1260 log_manager_
.current_log()->set_hardware_class(hardware_class_
);
1262 // Put incremental data (histogram deltas, and realtime stats deltas) at the
1263 // end of all log transmissions (initial log handles this separately).
1264 // RecordIncrementalStabilityElements only exists on the derived
1265 // MetricsLog class.
1266 MetricsLog
* current_log
=
1267 static_cast<MetricsLog
*>(log_manager_
.current_log());
1268 DCHECK(current_log
);
1269 std::vector
<chrome_variations::ActiveGroupId
> synthetic_trials
;
1270 GetCurrentSyntheticFieldTrials(&synthetic_trials
);
1271 current_log
->RecordEnvironment(plugins_
, google_update_metrics_
,
1273 PrefService
* pref
= g_browser_process
->local_state();
1274 current_log
->RecordStabilityMetrics(GetIncrementalUptime(pref
),
1275 MetricsLog::ONGOING_LOG
);
1277 RecordCurrentHistograms();
1279 log_manager_
.FinishCurrentLog();
1282 void MetricsService::PushPendingLogsToPersistentStorage() {
1283 if (state_
< SENDING_INITIAL_STABILITY_LOG
)
1284 return; // We didn't and still don't have time to get plugin list etc.
1286 if (log_manager_
.has_staged_log()) {
1287 // We may race here, and send second copy of the log later.
1288 MetricsLogManager::StoreType store_type
;
1289 if (current_fetch_
.get())
1290 store_type
= MetricsLogManager::PROVISIONAL_STORE
;
1292 store_type
= MetricsLogManager::NORMAL_STORE
;
1293 log_manager_
.StoreStagedLogAsUnsent(store_type
);
1295 DCHECK(!log_manager_
.has_staged_log());
1297 log_manager_
.PersistUnsentLogs();
1299 // If there was a staged and/or current log, then there is now at least one
1300 // log waiting to be uploaded.
1301 if (log_manager_
.has_unsent_logs())
1302 state_
= SENDING_OLD_LOGS
;
1305 //------------------------------------------------------------------------------
1306 // Transmission of logs methods
1308 void MetricsService::StartSchedulerIfNecessary() {
1309 // Never schedule cutting or uploading of logs in test mode.
1310 if (test_mode_active_
)
1313 // Even if reporting is disabled, the scheduler is needed to trigger the
1314 // creation of the initial log, which must be done in order for any logs to be
1315 // persisted on shutdown or backgrounding.
1316 if (recording_active() &&
1317 (reporting_active() || state_
< SENDING_INITIAL_STABILITY_LOG
)) {
1318 scheduler_
->Start();
1322 void MetricsService::StartScheduledUpload() {
1323 // If we're getting no notifications, then the log won't have much in it, and
1324 // it's possible the computer is about to go to sleep, so don't upload and
1325 // stop the scheduler.
1326 // If recording has been turned off, the scheduler doesn't need to run.
1327 // If reporting is off, proceed if the initial log hasn't been created, since
1328 // that has to happen in order for logs to be cut and stored when persisting.
1329 // TODO(stuartmorgan): Call Stop() on the schedule when reporting and/or
1330 // recording are turned off instead of letting it fire and then aborting.
1331 if (idle_since_last_transmission_
||
1332 !recording_active() ||
1333 (!reporting_active() && state_
>= SENDING_INITIAL_STABILITY_LOG
)) {
1335 scheduler_
->UploadCancelled();
1339 // If the callback was to upload an old log, but there no longer is one,
1340 // just report success back to the scheduler to begin the ongoing log
1342 // TODO(stuartmorgan): Consider removing the distinction between
1343 // SENDING_OLD_LOGS and SENDING_CURRENT_LOGS to simplify the state machine
1344 // now that the log upload flow is the same for both modes.
1345 if (state_
== SENDING_OLD_LOGS
&& !log_manager_
.has_unsent_logs()) {
1346 state_
= SENDING_CURRENT_LOGS
;
1347 scheduler_
->UploadFinished(true /* healthy */, false /* no unsent logs */);
1350 // If there are unsent logs, send the next one. If not, start the asynchronous
1351 // process of finalizing the current log for upload.
1352 if (state_
== SENDING_OLD_LOGS
) {
1353 DCHECK(log_manager_
.has_unsent_logs());
1354 log_manager_
.StageNextLogForUpload();
1357 StartFinalLogInfoCollection();
1361 void MetricsService::StartFinalLogInfoCollection() {
1362 // Begin the multi-step process of collecting memory usage histograms:
1363 // First spawn a task to collect the memory details; when that task is
1364 // finished, it will call OnMemoryDetailCollectionDone. That will in turn
1365 // call HistogramSynchronization to collect histograms from all renderers and
1366 // then call OnHistogramSynchronizationDone to continue processing.
1367 DCHECK(!waiting_for_asynchronous_reporting_step_
);
1368 waiting_for_asynchronous_reporting_step_
= true;
1370 base::Closure callback
=
1371 base::Bind(&MetricsService::OnMemoryDetailCollectionDone
,
1372 self_ptr_factory_
.GetWeakPtr());
1374 scoped_refptr
<MetricsMemoryDetails
> details(
1375 new MetricsMemoryDetails(callback
));
1376 details
->StartFetch(MemoryDetails::UPDATE_USER_METRICS
);
1378 // Collect WebCore cache information to put into a histogram.
1379 for (content::RenderProcessHost::iterator
i(
1380 content::RenderProcessHost::AllHostsIterator());
1381 !i
.IsAtEnd(); i
.Advance())
1382 i
.GetCurrentValue()->Send(new ChromeViewMsg_GetCacheResourceStats());
1385 void MetricsService::OnMemoryDetailCollectionDone() {
1386 DCHECK(IsSingleThreaded());
1387 // This function should only be called as the callback from an ansynchronous
1389 DCHECK(waiting_for_asynchronous_reporting_step_
);
1391 // Create a callback_task for OnHistogramSynchronizationDone.
1392 base::Closure callback
= base::Bind(
1393 &MetricsService::OnHistogramSynchronizationDone
,
1394 self_ptr_factory_
.GetWeakPtr());
1396 base::TimeDelta timeout
=
1397 base::TimeDelta::FromMilliseconds(kMaxHistogramGatheringWaitDuration
);
1399 DCHECK_EQ(num_async_histogram_fetches_in_progress_
, 0);
1401 #if defined(OS_ANDROID)
1402 // Android has no service process.
1403 num_async_histogram_fetches_in_progress_
= 1;
1405 num_async_histogram_fetches_in_progress_
= 2;
1406 // Run requests to service and content in parallel.
1407 if (!ServiceProcessControl::GetInstance()->GetHistograms(callback
, timeout
)) {
1408 // Assume |num_async_histogram_fetches_in_progress_| is not changed by
1409 // |GetHistograms()|.
1410 DCHECK_EQ(num_async_histogram_fetches_in_progress_
, 2);
1411 // Assign |num_async_histogram_fetches_in_progress_| above and decrement it
1412 // here to make code work even if |GetHistograms()| fired |callback|.
1413 --num_async_histogram_fetches_in_progress_
;
1415 #endif // OS_ANDROID
1417 // Set up the callback to task to call after we receive histograms from all
1418 // child processes. Wait time specifies how long to wait before absolutely
1419 // calling us back on the task.
1420 content::FetchHistogramsAsynchronously(base::MessageLoop::current(), callback
,
1424 void MetricsService::OnHistogramSynchronizationDone() {
1425 DCHECK(IsSingleThreaded());
1426 // This function should only be called as the callback from an ansynchronous
1428 DCHECK(waiting_for_asynchronous_reporting_step_
);
1429 DCHECK_GT(num_async_histogram_fetches_in_progress_
, 0);
1431 // Check if all expected requests finished.
1432 if (--num_async_histogram_fetches_in_progress_
> 0)
1435 waiting_for_asynchronous_reporting_step_
= false;
1436 OnFinalLogInfoCollectionDone();
1439 void MetricsService::OnFinalLogInfoCollectionDone() {
1440 // If somehow there is a fetch in progress, we return and hope things work
1441 // out. The scheduler isn't informed since if this happens, the scheduler
1442 // will get a response from the upload.
1443 DCHECK(!current_fetch_
.get());
1444 if (current_fetch_
.get())
1447 // Abort if metrics were turned off during the final info gathering.
1448 if (!recording_active()) {
1450 scheduler_
->UploadCancelled();
1456 // If logs shouldn't be uploaded, stop here. It's important that this check
1457 // be after StageNewLog(), otherwise the previous logs will never be loaded,
1458 // and thus the open log won't be persisted.
1459 // TODO(stuartmorgan): This is unnecessarily complicated; restructure loading
1460 // of previous logs to not require running part of the upload logic.
1461 // http://crbug.com/157337
1462 if (!reporting_active()) {
1464 scheduler_
->UploadCancelled();
1471 void MetricsService::StageNewLog() {
1472 if (log_manager_
.has_staged_log())
1477 case INIT_TASK_SCHEDULED
: // We should be further along by now.
1481 case INIT_TASK_DONE
:
1482 if (has_initial_stability_log_
) {
1483 // There's an initial stability log, ready to send.
1484 log_manager_
.StageNextLogForUpload();
1485 has_initial_stability_log_
= false;
1486 state_
= SENDING_INITIAL_STABILITY_LOG
;
1488 // TODO(asvitkine): When the field trial is removed, the |log_type|
1489 // arg should be removed and PrepareInitialMetricsLog() should always
1490 // use ONGOING_LOG. Use INITIAL_LOG only to match to the old behavior
1491 // when the field trial is off.
1492 MetricsLog::LogType log_type
= SendSeparateInitialStabilityLog() ?
1493 MetricsLog::ONGOING_LOG
: MetricsLog::INITIAL_LOG
;
1494 PrepareInitialMetricsLog(log_type
);
1495 // If the stability log field trial is off, load unsent logs from local
1496 // state here. Otherwise, they have already been loaded earlier.
1497 if (log_type
== MetricsLog::INITIAL_LOG
)
1498 log_manager_
.LoadPersistedUnsentLogs();
1499 state_
= SENDING_INITIAL_METRICS_LOG
;
1503 case SENDING_OLD_LOGS
:
1504 NOTREACHED(); // Shouldn't be staging a new log during old log sending.
1507 case SENDING_CURRENT_LOGS
:
1510 log_manager_
.StageNextLogForUpload();
1518 DCHECK(log_manager_
.has_staged_log());
1521 void MetricsService::PrepareInitialStabilityLog() {
1522 DCHECK_EQ(INITIALIZED
, state_
);
1523 PrefService
* pref
= g_browser_process
->local_state();
1524 DCHECK_NE(0, pref
->GetInteger(prefs::kStabilityCrashCount
));
1526 scoped_ptr
<MetricsLog
> initial_stability_log(
1527 new MetricsLog(client_id_
, session_id_
));
1528 if (!initial_stability_log
->LoadSavedEnvironmentFromPrefs())
1530 initial_stability_log
->RecordStabilityMetrics(base::TimeDelta(),
1531 MetricsLog::INITIAL_LOG
);
1532 log_manager_
.LoadPersistedUnsentLogs();
1534 log_manager_
.PauseCurrentLog();
1535 log_manager_
.BeginLoggingWithLog(initial_stability_log
.release(),
1536 MetricsLog::INITIAL_LOG
);
1537 log_manager_
.FinishCurrentLog();
1538 log_manager_
.ResumePausedLog();
1540 // Store unsent logs, including the stability log that was just saved, so
1541 // that they're not lost in case of a crash before upload time.
1542 log_manager_
.PersistUnsentLogs();
1544 has_initial_stability_log_
= true;
1547 void MetricsService::PrepareInitialMetricsLog(MetricsLog::LogType log_type
) {
1548 DCHECK(state_
== INIT_TASK_DONE
|| state_
== SENDING_INITIAL_STABILITY_LOG
);
1549 initial_metrics_log_
->set_hardware_class(hardware_class_
);
1551 std::vector
<chrome_variations::ActiveGroupId
> synthetic_trials
;
1552 GetCurrentSyntheticFieldTrials(&synthetic_trials
);
1553 initial_metrics_log_
->RecordEnvironment(plugins_
, google_update_metrics_
,
1555 PrefService
* pref
= g_browser_process
->local_state();
1556 initial_metrics_log_
->RecordStabilityMetrics(GetIncrementalUptime(pref
),
1559 // Histograms only get written to the current log, so make the new log current
1560 // before writing them.
1561 log_manager_
.PauseCurrentLog();
1562 log_manager_
.BeginLoggingWithLog(initial_metrics_log_
.release(), log_type
);
1563 RecordCurrentHistograms();
1564 log_manager_
.FinishCurrentLog();
1565 log_manager_
.ResumePausedLog();
1567 DCHECK(!log_manager_
.has_staged_log());
1568 log_manager_
.StageNextLogForUpload();
1571 void MetricsService::SendStagedLog() {
1572 DCHECK(log_manager_
.has_staged_log());
1574 PrepareFetchWithStagedLog();
1576 bool upload_created
= (current_fetch_
.get() != NULL
);
1577 UMA_HISTOGRAM_BOOLEAN("UMA.UploadCreation", upload_created
);
1578 if (!upload_created
) {
1579 // Compression failed, and log discarded :-/.
1580 // Skip this upload and hope things work out next time.
1581 log_manager_
.DiscardStagedLog();
1582 scheduler_
->UploadCancelled();
1586 DCHECK(!waiting_for_asynchronous_reporting_step_
);
1587 waiting_for_asynchronous_reporting_step_
= true;
1589 current_fetch_
->Start();
1591 HandleIdleSinceLastTransmission(true);
1594 void MetricsService::PrepareFetchWithStagedLog() {
1595 DCHECK(log_manager_
.has_staged_log());
1597 // Prepare the protobuf version.
1598 DCHECK(!current_fetch_
.get());
1599 if (log_manager_
.has_staged_log()) {
1600 current_fetch_
.reset(net::URLFetcher::Create(
1601 GURL(kServerUrl
), net::URLFetcher::POST
, this));
1602 current_fetch_
->SetRequestContext(
1603 g_browser_process
->system_request_context());
1605 std::string log_text
= log_manager_
.staged_log_text();
1606 std::string compressed_log_text
;
1607 bool compression_successful
= chrome::GzipCompress(log_text
,
1608 &compressed_log_text
);
1609 DCHECK(compression_successful
);
1610 if (compression_successful
) {
1611 current_fetch_
->SetUploadData(kMimeType
, compressed_log_text
);
1612 // Tell the server that we're uploading gzipped protobufs.
1613 current_fetch_
->SetExtraRequestHeaders("content-encoding: gzip");
1614 const std::string hash
=
1615 base::HexEncode(log_manager_
.staged_log_hash().data(),
1616 log_manager_
.staged_log_hash().size());
1617 DCHECK(!hash
.empty());
1618 current_fetch_
->AddExtraRequestHeader("X-Chrome-UMA-Log-SHA1: " + hash
);
1619 UMA_HISTOGRAM_PERCENTAGE(
1620 "UMA.ProtoCompressionRatio",
1621 100 * compressed_log_text
.size() / log_text
.size());
1622 UMA_HISTOGRAM_CUSTOM_COUNTS(
1623 "UMA.ProtoGzippedKBSaved",
1624 (log_text
.size() - compressed_log_text
.size()) / 1024,
1628 // We already drop cookies server-side, but we might as well strip them out
1629 // client-side as well.
1630 current_fetch_
->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES
|
1631 net::LOAD_DO_NOT_SEND_COOKIES
);
1635 void MetricsService::OnURLFetchComplete(const net::URLFetcher
* source
) {
1636 DCHECK(waiting_for_asynchronous_reporting_step_
);
1638 // We're not allowed to re-use the existing |URLFetcher|s, so free them here.
1639 // Note however that |source| is aliased to the fetcher, so we should be
1640 // careful not to delete it too early.
1641 DCHECK_EQ(current_fetch_
.get(), source
);
1642 scoped_ptr
<net::URLFetcher
> s(current_fetch_
.Pass());
1644 int response_code
= source
->GetResponseCode();
1646 // Log a histogram to track response success vs. failure rates.
1647 UMA_HISTOGRAM_ENUMERATION("UMA.UploadResponseStatus.Protobuf",
1648 ResponseCodeToStatus(response_code
),
1649 NUM_RESPONSE_STATUSES
);
1651 // If the upload was provisionally stored, drop it now that the upload is
1652 // known to have gone through.
1653 log_manager_
.DiscardLastProvisionalStore();
1655 bool upload_succeeded
= response_code
== 200;
1657 // Provide boolean for error recovery (allow us to ignore response_code).
1658 bool discard_log
= false;
1659 const size_t log_size
= log_manager_
.staged_log_text().length();
1660 if (!upload_succeeded
&& log_size
> kUploadLogAvoidRetransmitSize
) {
1661 UMA_HISTOGRAM_COUNTS("UMA.Large Rejected Log was Discarded",
1662 static_cast<int>(log_size
));
1664 } else if (response_code
== 400) {
1665 // Bad syntax. Retransmission won't work.
1669 if (upload_succeeded
|| discard_log
)
1670 log_manager_
.DiscardStagedLog();
1672 waiting_for_asynchronous_reporting_step_
= false;
1674 if (!log_manager_
.has_staged_log()) {
1676 case SENDING_INITIAL_STABILITY_LOG
:
1677 // Store the updated list to disk now that the removed log is uploaded.
1678 log_manager_
.PersistUnsentLogs();
1679 PrepareInitialMetricsLog(MetricsLog::ONGOING_LOG
);
1681 state_
= SENDING_INITIAL_METRICS_LOG
;
1684 case SENDING_INITIAL_METRICS_LOG
:
1685 // The initial metrics log never gets persisted to local state, so it's
1686 // not necessary to call log_manager_.PersistUnsentLogs() here.
1687 // TODO(asvitkine): It should be persisted like the initial stability
1688 // log and old unsent logs. http://crbug.com/328417
1689 state_
= log_manager_
.has_unsent_logs() ? SENDING_OLD_LOGS
1690 : SENDING_CURRENT_LOGS
;
1693 case SENDING_OLD_LOGS
:
1694 // Store the updated list to disk now that the removed log is uploaded.
1695 log_manager_
.PersistUnsentLogs();
1696 if (!log_manager_
.has_unsent_logs())
1697 state_
= SENDING_CURRENT_LOGS
;
1700 case SENDING_CURRENT_LOGS
:
1708 if (log_manager_
.has_unsent_logs())
1709 DCHECK_LT(state_
, SENDING_CURRENT_LOGS
);
1712 // Error 400 indicates a problem with the log, not with the server, so
1713 // don't consider that a sign that the server is in trouble.
1714 bool server_is_healthy
= upload_succeeded
|| response_code
== 400;
1715 // Don't notify the scheduler that the upload is finished if we've only sent
1716 // the initial stability log, but not yet the initial metrics log (treat the
1717 // two as a single unit of work as far as the scheduler is concerned).
1718 if (state_
!= SENDING_INITIAL_METRICS_LOG
) {
1719 scheduler_
->UploadFinished(server_is_healthy
,
1720 log_manager_
.has_unsent_logs());
1723 // Collect network stats if UMA upload succeeded.
1724 IOThread
* io_thread
= g_browser_process
->io_thread();
1725 if (server_is_healthy
&& io_thread
) {
1726 chrome_browser_net::CollectNetworkStats(network_stats_server_
, io_thread
);
1727 chrome_browser_net::CollectPipeliningCapabilityStatsOnUIThread(
1728 http_pipelining_test_server_
, io_thread
);
1730 chrome::CollectTimeTicksStats();
1735 void MetricsService::IncrementPrefValue(const char* path
) {
1736 PrefService
* pref
= g_browser_process
->local_state();
1738 int value
= pref
->GetInteger(path
);
1739 pref
->SetInteger(path
, value
+ 1);
1742 void MetricsService::IncrementLongPrefsValue(const char* path
) {
1743 PrefService
* pref
= g_browser_process
->local_state();
1745 int64 value
= pref
->GetInt64(path
);
1746 pref
->SetInt64(path
, value
+ 1);
1749 void MetricsService::LogLoadStarted(content::WebContents
* web_contents
) {
1750 content::RecordAction(base::UserMetricsAction("PageLoad"));
1751 HISTOGRAM_ENUMERATION("Chrome.UmaPageloadCounter", 1, 2);
1752 IncrementPrefValue(prefs::kStabilityPageLoadCount
);
1753 IncrementLongPrefsValue(prefs::kUninstallMetricsPageLoadCount
);
1754 // We need to save the prefs, as page load count is a critical stat, and it
1755 // might be lost due to a crash :-(.
1758 void MetricsService::LogRendererCrash(content::RenderProcessHost
* host
,
1759 base::TerminationStatus status
,
1761 bool was_extension_process
=
1762 extensions::ProcessMap::Get(host
->GetBrowserContext())
1763 ->Contains(host
->GetID());
1764 if (status
== base::TERMINATION_STATUS_PROCESS_CRASHED
||
1765 status
== base::TERMINATION_STATUS_ABNORMAL_TERMINATION
) {
1766 if (was_extension_process
) {
1767 IncrementPrefValue(prefs::kStabilityExtensionRendererCrashCount
);
1769 UMA_HISTOGRAM_SPARSE_SLOWLY("CrashExitCodes.Extension",
1770 MapCrashExitCodeForHistogram(exit_code
));
1772 IncrementPrefValue(prefs::kStabilityRendererCrashCount
);
1774 UMA_HISTOGRAM_SPARSE_SLOWLY("CrashExitCodes.Renderer",
1775 MapCrashExitCodeForHistogram(exit_code
));
1778 UMA_HISTOGRAM_PERCENTAGE("BrowserRenderProcessHost.ChildCrashes",
1779 was_extension_process
? 2 : 1);
1780 } else if (status
== base::TERMINATION_STATUS_PROCESS_WAS_KILLED
) {
1781 UMA_HISTOGRAM_PERCENTAGE("BrowserRenderProcessHost.ChildKills",
1782 was_extension_process
? 2 : 1);
1783 } else if (status
== base::TERMINATION_STATUS_STILL_RUNNING
) {
1784 UMA_HISTOGRAM_PERCENTAGE("BrowserRenderProcessHost.DisconnectedAlive",
1785 was_extension_process
? 2 : 1);
1789 void MetricsService::LogRendererHang() {
1790 IncrementPrefValue(prefs::kStabilityRendererHangCount
);
1793 bool MetricsService::UmaMetricsProperlyShutdown() {
1794 CHECK(clean_shutdown_status_
== CLEANLY_SHUTDOWN
||
1795 clean_shutdown_status_
== NEED_TO_SHUTDOWN
);
1796 return clean_shutdown_status_
== CLEANLY_SHUTDOWN
;
1799 void MetricsService::RegisterSyntheticFieldTrial(
1800 const SyntheticTrialGroup
& trial
) {
1801 for (size_t i
= 0; i
< synthetic_trial_groups_
.size(); ++i
) {
1802 if (synthetic_trial_groups_
[i
].id
.name
== trial
.id
.name
) {
1803 if (synthetic_trial_groups_
[i
].id
.group
!= trial
.id
.group
) {
1804 synthetic_trial_groups_
[i
].id
.group
= trial
.id
.group
;
1805 synthetic_trial_groups_
[i
].start_time
= trial
.start_time
;
1811 SyntheticTrialGroup
trial_group(
1812 trial
.id
.name
, trial
.id
.group
, base::TimeTicks::Now());
1813 synthetic_trial_groups_
.push_back(trial_group
);
1816 void MetricsService::GetCurrentSyntheticFieldTrials(
1817 std::vector
<chrome_variations::ActiveGroupId
>* synthetic_trials
) {
1818 DCHECK(synthetic_trials
);
1819 synthetic_trials
->clear();
1820 const MetricsLog
* current_log
=
1821 static_cast<const MetricsLog
*>(log_manager_
.current_log());
1822 for (size_t i
= 0; i
< synthetic_trial_groups_
.size(); ++i
) {
1823 if (synthetic_trial_groups_
[i
].start_time
<= current_log
->creation_time())
1824 synthetic_trials
->push_back(synthetic_trial_groups_
[i
].id
);
1828 void MetricsService::LogCleanShutdown() {
1829 // Redundant hack to write pref ASAP.
1830 MarkAppCleanShutdownAndCommit();
1832 // Redundant setting to assure that we always reset this value at shutdown
1833 // (and that we don't use some alternate path, and not call LogCleanShutdown).
1834 clean_shutdown_status_
= CLEANLY_SHUTDOWN
;
1836 RecordBooleanPrefValue(prefs::kStabilityExitedCleanly
, true);
1837 PrefService
* pref
= g_browser_process
->local_state();
1838 pref
->SetInteger(prefs::kStabilityExecutionPhase
,
1839 MetricsService::SHUTDOWN_COMPLETE
);
1842 #if defined(OS_CHROMEOS)
1843 void MetricsService::LogChromeOSCrash(const std::string
&crash_type
) {
1844 if (crash_type
== "user")
1845 IncrementPrefValue(prefs::kStabilityOtherUserCrashCount
);
1846 else if (crash_type
== "kernel")
1847 IncrementPrefValue(prefs::kStabilityKernelCrashCount
);
1848 else if (crash_type
== "uncleanshutdown")
1849 IncrementPrefValue(prefs::kStabilitySystemUncleanShutdownCount
);
1851 NOTREACHED() << "Unexpected Chrome OS crash type " << crash_type
;
1852 // Wake up metrics logs sending if necessary now that new
1853 // log data is available.
1854 HandleIdleSinceLastTransmission(false);
1856 #endif // OS_CHROMEOS
1858 void MetricsService::LogPluginLoadingError(const base::FilePath
& plugin_path
) {
1859 content::WebPluginInfo plugin
;
1861 content::PluginService::GetInstance()->GetPluginInfoByPath(plugin_path
,
1864 ChildProcessStats
& stats
= child_process_stats_buffer_
[plugin
.name
];
1865 // Initialize the type if this entry is new.
1866 if (stats
.process_type
== content::PROCESS_TYPE_UNKNOWN
) {
1867 // The plug-in process might not actually of type PLUGIN (which means
1868 // NPAPI), but we only care that it is *a* plug-in process.
1869 stats
.process_type
= content::PROCESS_TYPE_PLUGIN
;
1871 DCHECK(IsPluginProcess(stats
.process_type
));
1873 stats
.loading_errors
++;
1876 MetricsService::ChildProcessStats
& MetricsService::GetChildProcessStats(
1877 const content::ChildProcessData
& data
) {
1878 const base::string16
& child_name
= data
.name
;
1879 if (!ContainsKey(child_process_stats_buffer_
, child_name
)) {
1880 child_process_stats_buffer_
[child_name
] =
1881 ChildProcessStats(data
.process_type
);
1883 return child_process_stats_buffer_
[child_name
];
1886 void MetricsService::RecordPluginChanges(PrefService
* pref
) {
1887 ListPrefUpdate
update(pref
, prefs::kStabilityPluginStats
);
1888 base::ListValue
* plugins
= update
.Get();
1891 for (base::ListValue::iterator value_iter
= plugins
->begin();
1892 value_iter
!= plugins
->end(); ++value_iter
) {
1893 if (!(*value_iter
)->IsType(base::Value::TYPE_DICTIONARY
)) {
1898 base::DictionaryValue
* plugin_dict
=
1899 static_cast<base::DictionaryValue
*>(*value_iter
);
1900 std::string plugin_name
;
1901 plugin_dict
->GetString(prefs::kStabilityPluginName
, &plugin_name
);
1902 if (plugin_name
.empty()) {
1907 // TODO(viettrungluu): remove conversions
1908 base::string16 name16
= base::UTF8ToUTF16(plugin_name
);
1909 if (child_process_stats_buffer_
.find(name16
) ==
1910 child_process_stats_buffer_
.end()) {
1914 ChildProcessStats stats
= child_process_stats_buffer_
[name16
];
1915 if (stats
.process_launches
) {
1917 plugin_dict
->GetInteger(prefs::kStabilityPluginLaunches
, &launches
);
1918 launches
+= stats
.process_launches
;
1919 plugin_dict
->SetInteger(prefs::kStabilityPluginLaunches
, launches
);
1921 if (stats
.process_crashes
) {
1923 plugin_dict
->GetInteger(prefs::kStabilityPluginCrashes
, &crashes
);
1924 crashes
+= stats
.process_crashes
;
1925 plugin_dict
->SetInteger(prefs::kStabilityPluginCrashes
, crashes
);
1927 if (stats
.instances
) {
1929 plugin_dict
->GetInteger(prefs::kStabilityPluginInstances
, &instances
);
1930 instances
+= stats
.instances
;
1931 plugin_dict
->SetInteger(prefs::kStabilityPluginInstances
, instances
);
1933 if (stats
.loading_errors
) {
1934 int loading_errors
= 0;
1935 plugin_dict
->GetInteger(prefs::kStabilityPluginLoadingErrors
,
1937 loading_errors
+= stats
.loading_errors
;
1938 plugin_dict
->SetInteger(prefs::kStabilityPluginLoadingErrors
,
1942 child_process_stats_buffer_
.erase(name16
);
1945 // Now go through and add dictionaries for plugins that didn't already have
1946 // reports in Local State.
1947 for (std::map
<base::string16
, ChildProcessStats
>::iterator cache_iter
=
1948 child_process_stats_buffer_
.begin();
1949 cache_iter
!= child_process_stats_buffer_
.end(); ++cache_iter
) {
1950 ChildProcessStats stats
= cache_iter
->second
;
1952 // Insert only plugins information into the plugins list.
1953 if (!IsPluginProcess(stats
.process_type
))
1956 // TODO(viettrungluu): remove conversion
1957 std::string plugin_name
= base::UTF16ToUTF8(cache_iter
->first
);
1959 base::DictionaryValue
* plugin_dict
= new base::DictionaryValue
;
1961 plugin_dict
->SetString(prefs::kStabilityPluginName
, plugin_name
);
1962 plugin_dict
->SetInteger(prefs::kStabilityPluginLaunches
,
1963 stats
.process_launches
);
1964 plugin_dict
->SetInteger(prefs::kStabilityPluginCrashes
,
1965 stats
.process_crashes
);
1966 plugin_dict
->SetInteger(prefs::kStabilityPluginInstances
,
1968 plugin_dict
->SetInteger(prefs::kStabilityPluginLoadingErrors
,
1969 stats
.loading_errors
);
1970 plugins
->Append(plugin_dict
);
1972 child_process_stats_buffer_
.clear();
1975 bool MetricsService::CanLogNotification() {
1976 // We simply don't log anything to UMA if there is a single incognito
1977 // session visible. The problem is that we always notify using the orginal
1978 // profile in order to simplify notification processing.
1979 return !chrome::IsOffTheRecordSessionActive();
1982 void MetricsService::RecordBooleanPrefValue(const char* path
, bool value
) {
1983 DCHECK(IsSingleThreaded());
1985 PrefService
* pref
= g_browser_process
->local_state();
1988 pref
->SetBoolean(path
, value
);
1989 RecordCurrentState(pref
);
1992 void MetricsService::RecordCurrentState(PrefService
* pref
) {
1993 pref
->SetInt64(prefs::kStabilityLastTimestampSec
, Time::Now().ToTimeT());
1995 RecordPluginChanges(pref
);
1999 bool MetricsService::IsPluginProcess(int process_type
) {
2000 return (process_type
== content::PROCESS_TYPE_PLUGIN
||
2001 process_type
== content::PROCESS_TYPE_PPAPI_PLUGIN
||
2002 process_type
== content::PROCESS_TYPE_PPAPI_BROKER
);
2005 #if defined(OS_CHROMEOS)
2006 void MetricsService::StartExternalMetrics() {
2007 external_metrics_
= new chromeos::ExternalMetrics
;
2008 external_metrics_
->Start();
2013 bool MetricsServiceHelper::IsMetricsReportingEnabled() {
2014 bool result
= false;
2015 const PrefService
* local_state
= g_browser_process
->local_state();
2017 const PrefService::Preference
* uma_pref
=
2018 local_state
->FindPreference(prefs::kMetricsReportingEnabled
);
2020 bool success
= uma_pref
->GetValue()->GetAsBoolean(&result
);