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);
486 #if defined(OS_ANDROID)
487 RegisterPrefsAndroid(registry);
488 #endif // defined(OS_ANDROID)
492 void MetricsService::DiscardOldStabilityStats(PrefService* local_state) {
493 local_state->SetBoolean(prefs::kStabilityExitedCleanly, true);
494 local_state->SetInteger(prefs::kStabilityExecutionPhase, UNINITIALIZED_PHASE);
495 local_state->SetBoolean(prefs::kStabilitySessionEndCompleted, true);
497 local_state->SetInteger(prefs::kStabilityIncompleteSessionEndCount, 0);
498 local_state->SetInteger(prefs::kStabilityBreakpadRegistrationSuccess, 0);
499 local_state->SetInteger(prefs::kStabilityBreakpadRegistrationFail, 0);
500 local_state->SetInteger(prefs::kStabilityDebuggerPresent, 0);
501 local_state->SetInteger(prefs::kStabilityDebuggerNotPresent, 0);
503 local_state->SetInteger(prefs::kStabilityLaunchCount, 0);
504 local_state->SetInteger(prefs::kStabilityCrashCount, 0);
506 local_state->SetInteger(prefs::kStabilityPageLoadCount, 0);
507 local_state->SetInteger(prefs::kStabilityRendererCrashCount, 0);
508 local_state->SetInteger(prefs::kStabilityRendererHangCount, 0);
510 local_state->SetInt64(prefs::kStabilityLaunchTimeSec, 0);
511 local_state->SetInt64(prefs::kStabilityLastTimestampSec, 0);
513 local_state->ClearPref(prefs::kStabilityPluginStats);
515 local_state->ClearPref(prefs::kMetricsInitialLogs);
516 local_state->ClearPref(prefs::kMetricsOngoingLogs);
518 #if defined(OS_ANDROID)
519 DiscardOldStabilityStatsAndroid(local_state);
520 #endif // defined(OS_ANDROID)
523 MetricsService::MetricsService()
524 : recording_active_(false),
525 reporting_active_(false),
526 test_mode_active_(false),
528 has_initial_stability_log_(false),
529 low_entropy_source_(kLowEntropySourceNotSet),
530 idle_since_last_transmission_(false),
533 self_ptr_factory_(this),
534 state_saver_factory_(this),
535 waiting_for_asynchronous_reporting_step_(false),
536 num_async_histogram_fetches_in_progress_(0),
537 entropy_source_returned_(LAST_ENTROPY_NONE) {
538 DCHECK(IsSingleThreaded());
540 log_manager_.set_log_serializer(new MetricsLogSerializer);
541 log_manager_.set_max_ongoing_log_store_size(kUploadLogAvoidRetransmitSize);
543 BrowserChildProcessObserver::Add(this);
546 MetricsService::~MetricsService() {
549 BrowserChildProcessObserver::Remove(this);
552 void MetricsService::InitializeMetricsRecordingState(
553 ReportingState reporting_state) {
554 InitializeMetricsState(reporting_state);
556 base::Closure callback = base::Bind(&MetricsService::StartScheduledUpload,
557 self_ptr_factory_.GetWeakPtr());
558 scheduler_.reset(new MetricsReportingScheduler(callback));
561 void MetricsService::Start() {
562 HandleIdleSinceLastTransmission(false);
567 void MetricsService::StartRecordingForTests() {
568 test_mode_active_ = true;
573 void MetricsService::Stop() {
574 HandleIdleSinceLastTransmission(false);
579 void MetricsService::EnableReporting() {
580 if (reporting_active_)
582 reporting_active_ = true;
583 StartSchedulerIfNecessary();
586 void MetricsService::DisableReporting() {
587 reporting_active_ = false;
590 std::string MetricsService::GetClientId() {
594 scoped_ptr<const base::FieldTrial::EntropyProvider>
595 MetricsService::CreateEntropyProvider(ReportingState reporting_state) {
596 // For metrics reporting-enabled users, we combine the client ID and low
597 // entropy source to get the final entropy source. Otherwise, only use the low
599 // This has two useful properties:
600 // 1) It makes the entropy source less identifiable for parties that do not
601 // know the low entropy source.
602 // 2) It makes the final entropy source resettable.
603 const int low_entropy_source_value = GetLowEntropySource();
604 UMA_HISTOGRAM_SPARSE_SLOWLY("UMA.LowEntropySourceValue",
605 low_entropy_source_value);
606 if (reporting_state == REPORTING_ENABLED) {
607 if (entropy_source_returned_ == LAST_ENTROPY_NONE)
608 entropy_source_returned_ = LAST_ENTROPY_HIGH;
609 DCHECK_EQ(LAST_ENTROPY_HIGH, entropy_source_returned_);
610 const std::string high_entropy_source =
611 client_id_ + base::IntToString(low_entropy_source_value);
612 return scoped_ptr<const base::FieldTrial::EntropyProvider>(
613 new metrics::SHA1EntropyProvider(high_entropy_source));
616 if (entropy_source_returned_ == LAST_ENTROPY_NONE)
617 entropy_source_returned_ = LAST_ENTROPY_LOW;
618 DCHECK_EQ(LAST_ENTROPY_LOW, entropy_source_returned_);
620 #if defined(OS_ANDROID) || defined(OS_IOS)
621 return scoped_ptr<const base::FieldTrial::EntropyProvider>(
622 new metrics::CachingPermutedEntropyProvider(
623 g_browser_process->local_state(),
624 low_entropy_source_value,
625 kMaxLowEntropySize));
627 return scoped_ptr<const base::FieldTrial::EntropyProvider>(
628 new metrics::PermutedEntropyProvider(low_entropy_source_value,
629 kMaxLowEntropySize));
633 void MetricsService::ForceClientIdCreation() {
634 if (!client_id_.empty())
636 PrefService* pref = g_browser_process->local_state();
637 client_id_ = pref->GetString(prefs::kMetricsClientID);
638 if (!client_id_.empty())
641 client_id_ = GenerateClientID();
642 pref->SetString(prefs::kMetricsClientID, client_id_);
644 // Might as well make a note of how long this ID has existed
645 pref->SetString(prefs::kMetricsClientIDTimestamp,
646 base::Int64ToString(Time::Now().ToTimeT()));
649 void MetricsService::EnableRecording() {
650 DCHECK(IsSingleThreaded());
652 if (recording_active_)
654 recording_active_ = true;
656 ForceClientIdCreation();
657 crash_keys::SetClientID(client_id_);
658 if (!log_manager_.current_log())
661 SetUpNotifications(®istrar_, this);
662 base::RemoveActionCallback(action_callback_);
663 action_callback_ = base::Bind(&MetricsService::OnUserAction,
664 base::Unretained(this));
665 base::AddActionCallback(action_callback_);
668 void MetricsService::DisableRecording() {
669 DCHECK(IsSingleThreaded());
671 if (!recording_active_)
673 recording_active_ = false;
675 base::RemoveActionCallback(action_callback_);
676 registrar_.RemoveAll();
677 PushPendingLogsToPersistentStorage();
678 DCHECK(!log_manager_.has_staged_log());
681 bool MetricsService::recording_active() const {
682 DCHECK(IsSingleThreaded());
683 return recording_active_;
686 bool MetricsService::reporting_active() const {
687 DCHECK(IsSingleThreaded());
688 return reporting_active_;
692 void MetricsService::SetUpNotifications(
693 content::NotificationRegistrar* registrar,
694 content::NotificationObserver* observer) {
695 registrar->Add(observer, chrome::NOTIFICATION_BROWSER_OPENED,
696 content::NotificationService::AllBrowserContextsAndSources());
697 registrar->Add(observer, chrome::NOTIFICATION_BROWSER_CLOSED,
698 content::NotificationService::AllSources());
699 registrar->Add(observer, chrome::NOTIFICATION_TAB_PARENTED,
700 content::NotificationService::AllSources());
701 registrar->Add(observer, chrome::NOTIFICATION_TAB_CLOSING,
702 content::NotificationService::AllSources());
703 registrar->Add(observer, content::NOTIFICATION_LOAD_START,
704 content::NotificationService::AllSources());
705 registrar->Add(observer, content::NOTIFICATION_LOAD_STOP,
706 content::NotificationService::AllSources());
707 registrar->Add(observer, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
708 content::NotificationService::AllSources());
709 registrar->Add(observer, content::NOTIFICATION_RENDER_WIDGET_HOST_HANG,
710 content::NotificationService::AllSources());
711 registrar->Add(observer, chrome::NOTIFICATION_OMNIBOX_OPENED_URL,
712 content::NotificationService::AllSources());
715 void MetricsService::BrowserChildProcessHostConnected(
716 const content::ChildProcessData& data) {
717 GetChildProcessStats(data).process_launches++;
720 void MetricsService::BrowserChildProcessCrashed(
721 const content::ChildProcessData& data) {
722 GetChildProcessStats(data).process_crashes++;
723 // Exclude plugin crashes from the count below because we report them via
724 // a separate UMA metric.
725 if (!IsPluginProcess(data.process_type))
726 IncrementPrefValue(prefs::kStabilityChildProcessCrashCount);
729 void MetricsService::BrowserChildProcessInstanceCreated(
730 const content::ChildProcessData& data) {
731 GetChildProcessStats(data).instances++;
734 void MetricsService::Observe(int type,
735 const content::NotificationSource& source,
736 const content::NotificationDetails& details) {
737 DCHECK(log_manager_.current_log());
738 DCHECK(IsSingleThreaded());
740 if (!CanLogNotification())
744 case chrome::NOTIFICATION_BROWSER_OPENED:
745 case chrome::NOTIFICATION_BROWSER_CLOSED:
746 case chrome::NOTIFICATION_TAB_PARENTED:
747 case chrome::NOTIFICATION_TAB_CLOSING:
748 case content::NOTIFICATION_LOAD_STOP:
749 // These notifications are currently used only to break out of idle mode.
752 case content::NOTIFICATION_LOAD_START: {
753 content::NavigationController* controller =
754 content::Source<content::NavigationController>(source).ptr();
755 content::WebContents* web_contents = controller->GetWebContents();
756 LogLoadStarted(web_contents);
760 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: {
761 content::RenderProcessHost::RendererClosedDetails* process_details =
763 content::RenderProcessHost::RendererClosedDetails>(
765 content::RenderProcessHost* host =
766 content::Source<content::RenderProcessHost>(source).ptr();
768 host, process_details->status, process_details->exit_code);
772 case content::NOTIFICATION_RENDER_WIDGET_HOST_HANG:
776 case chrome::NOTIFICATION_OMNIBOX_OPENED_URL: {
777 MetricsLog* current_log =
778 static_cast<MetricsLog*>(log_manager_.current_log());
780 current_log->RecordOmniboxOpenedURL(
781 *content::Details<OmniboxLog>(details).ptr());
790 HandleIdleSinceLastTransmission(false);
793 void MetricsService::HandleIdleSinceLastTransmission(bool in_idle) {
794 // If there wasn't a lot of action, maybe the computer was asleep, in which
795 // case, the log transmissions should have stopped. Here we start them up
797 if (!in_idle && idle_since_last_transmission_)
798 StartSchedulerIfNecessary();
799 idle_since_last_transmission_ = in_idle;
802 void MetricsService::RecordStartOfSessionEnd() {
804 RecordBooleanPrefValue(prefs::kStabilitySessionEndCompleted, false);
807 void MetricsService::RecordCompletedSessionEnd() {
809 RecordBooleanPrefValue(prefs::kStabilitySessionEndCompleted, true);
812 #if defined(OS_ANDROID) || defined(OS_IOS)
813 void MetricsService::OnAppEnterBackground() {
816 MarkAppCleanShutdownAndCommit();
818 // At this point, there's no way of knowing when the process will be
819 // killed, so this has to be treated similar to a shutdown, closing and
820 // persisting all logs. Unlinke a shutdown, the state is primed to be ready
821 // to continue logging and uploading if the process does return.
822 if (recording_active() && state_ >= SENDING_INITIAL_STABILITY_LOG) {
823 PushPendingLogsToPersistentStorage();
824 // Persisting logs closes the current log, so start recording a new log
825 // immediately to capture any background work that might be done before the
826 // process is killed.
831 void MetricsService::OnAppEnterForeground() {
832 PrefService* pref = g_browser_process->local_state();
833 pref->SetBoolean(prefs::kStabilityExitedCleanly, false);
835 StartSchedulerIfNecessary();
838 void MetricsService::LogNeedForCleanShutdown() {
839 PrefService* pref = g_browser_process->local_state();
840 pref->SetBoolean(prefs::kStabilityExitedCleanly, false);
841 // Redundant setting to be sure we call for a clean shutdown.
842 clean_shutdown_status_ = NEED_TO_SHUTDOWN;
844 #endif // defined(OS_ANDROID) || defined(OS_IOS)
847 void MetricsService::SetExecutionPhase(ExecutionPhase execution_phase) {
848 execution_phase_ = execution_phase;
849 PrefService* pref = g_browser_process->local_state();
850 pref->SetInteger(prefs::kStabilityExecutionPhase, execution_phase_);
853 void MetricsService::RecordBreakpadRegistration(bool success) {
855 IncrementPrefValue(prefs::kStabilityBreakpadRegistrationFail);
857 IncrementPrefValue(prefs::kStabilityBreakpadRegistrationSuccess);
860 void MetricsService::RecordBreakpadHasDebugger(bool has_debugger) {
862 IncrementPrefValue(prefs::kStabilityDebuggerNotPresent);
864 IncrementPrefValue(prefs::kStabilityDebuggerPresent);
868 void MetricsService::CountBrowserCrashDumpAttempts() {
869 // Open the registry key for iteration.
870 base::win::RegKey regkey;
871 if (regkey.Open(HKEY_CURRENT_USER,
872 chrome::kBrowserCrashDumpAttemptsRegistryPath,
873 KEY_ALL_ACCESS) != ERROR_SUCCESS) {
877 // The values we're interested in counting are all prefixed with the version.
878 base::string16 chrome_version(base::ASCIIToUTF16(chrome::kChromeVersion));
880 // Track a list of values to delete. We don't modify the registry key while
881 // we're iterating over its values.
882 typedef std::vector<base::string16> StringVector;
883 StringVector to_delete;
885 // Iterate over the values in the key counting dumps with and without crashes.
886 // We directly walk the values instead of using RegistryValueIterator in order
887 // to read all of the values as DWORDS instead of strings.
890 int dumps_with_crash = 0;
891 int dumps_with_no_crash = 0;
892 for (int i = regkey.GetValueCount() - 1; i >= 0; --i) {
893 if (regkey.GetValueNameAt(i, &name) == ERROR_SUCCESS &&
894 StartsWith(name, chrome_version, false) &&
895 regkey.ReadValueDW(name.c_str(), &value) == ERROR_SUCCESS) {
896 to_delete.push_back(name);
898 ++dumps_with_no_crash;
904 // Delete the registry keys we've just counted.
905 for (StringVector::iterator i = to_delete.begin(); i != to_delete.end(); ++i)
906 regkey.DeleteValue(i->c_str());
908 // Capture the histogram samples.
909 if (dumps_with_crash != 0)
910 UMA_HISTOGRAM_COUNTS("Chrome.BrowserDumpsWithCrash", dumps_with_crash);
911 if (dumps_with_no_crash != 0)
912 UMA_HISTOGRAM_COUNTS("Chrome.BrowserDumpsWithNoCrash", dumps_with_no_crash);
913 int total_dumps = dumps_with_crash + dumps_with_no_crash;
914 if (total_dumps != 0)
915 UMA_HISTOGRAM_COUNTS("Chrome.BrowserCrashDumpAttempts", total_dumps);
917 #endif // defined(OS_WIN)
919 //------------------------------------------------------------------------------
921 //------------------------------------------------------------------------------
924 //------------------------------------------------------------------------------
925 // Initialization methods
927 void MetricsService::InitializeMetricsState(ReportingState reporting_state) {
928 #if defined(OS_POSIX)
929 network_stats_server_ = chrome_common_net::kEchoTestServerLocation;
930 http_pipelining_test_server_ = chrome_common_net::kPipelineTestServerBaseUrl;
932 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
933 network_stats_server_ = dist->GetNetworkStatsServer();
934 http_pipelining_test_server_ = dist->GetHttpPipeliningTestServer();
937 PrefService* pref = g_browser_process->local_state();
940 // TODO(asvitkine): Kill this logic when SendSeparateInitialStabilityLog() is
941 // is made the default behavior.
942 if ((pref->GetInt64(prefs::kStabilityStatsBuildTime)
943 != MetricsLog::GetBuildTime()) ||
944 (pref->GetString(prefs::kStabilityStatsVersion)
945 != MetricsLog::GetVersionString())) {
946 // This is a new version, so we don't want to confuse the stats about the
947 // old version with info that we upload.
948 DiscardOldStabilityStats(pref);
949 pref->SetString(prefs::kStabilityStatsVersion,
950 MetricsLog::GetVersionString());
951 pref->SetInt64(prefs::kStabilityStatsBuildTime,
952 MetricsLog::GetBuildTime());
955 session_id_ = pref->GetInteger(prefs::kMetricsSessionID);
957 #if defined(OS_ANDROID)
958 LogAndroidStabilityToPrefs(pref);
959 #endif // defined(OS_ANDROID)
961 if (!pref->GetBoolean(prefs::kStabilityExitedCleanly)) {
962 IncrementPrefValue(prefs::kStabilityCrashCount);
963 // Reset flag, and wait until we call LogNeedForCleanShutdown() before
965 pref->SetBoolean(prefs::kStabilityExitedCleanly, true);
967 // TODO(rtenneti): On windows, consider saving/getting execution_phase from
969 int execution_phase = pref->GetInteger(prefs::kStabilityExecutionPhase);
970 UMA_HISTOGRAM_SPARSE_SLOWLY("Chrome.Browser.CrashedExecutionPhase",
973 // If the previous session didn't exit cleanly, then prepare an initial
974 // stability log if UMA is enabled.
975 bool reporting_will_be_enabled = (reporting_state == REPORTING_ENABLED);
976 if (reporting_will_be_enabled && SendSeparateInitialStabilityLog())
977 PrepareInitialStabilityLog();
980 // Update session ID.
982 pref->SetInteger(prefs::kMetricsSessionID, session_id_);
984 // Stability bookkeeping
985 IncrementPrefValue(prefs::kStabilityLaunchCount);
987 DCHECK_EQ(UNINITIALIZED_PHASE, execution_phase_);
988 SetExecutionPhase(START_METRICS_RECORDING);
991 CountBrowserCrashDumpAttempts();
992 #endif // defined(OS_WIN)
994 if (!pref->GetBoolean(prefs::kStabilitySessionEndCompleted)) {
995 IncrementPrefValue(prefs::kStabilityIncompleteSessionEndCount);
996 // This is marked false when we get a WM_ENDSESSION.
997 pref->SetBoolean(prefs::kStabilitySessionEndCompleted, true);
1000 // Initialize uptime counters.
1001 const base::TimeDelta startup_uptime = GetIncrementalUptime(pref);
1002 DCHECK_EQ(0, startup_uptime.InMicroseconds());
1003 // For backwards compatibility, leave this intact in case Omaha is checking
1004 // them. prefs::kStabilityLastTimestampSec may also be useless now.
1005 // TODO(jar): Delete these if they have no uses.
1006 pref->SetInt64(prefs::kStabilityLaunchTimeSec, Time::Now().ToTimeT());
1008 // Bookkeeping for the uninstall metrics.
1009 IncrementLongPrefsValue(prefs::kUninstallLaunchCount);
1011 // Get stats on use of command line.
1012 const CommandLine* command_line(CommandLine::ForCurrentProcess());
1013 size_t common_commands = 0;
1014 if (command_line->HasSwitch(switches::kUserDataDir)) {
1016 UMA_HISTOGRAM_COUNTS_100("Chrome.CommandLineDatDirCount", 1);
1019 if (command_line->HasSwitch(switches::kApp)) {
1021 UMA_HISTOGRAM_COUNTS_100("Chrome.CommandLineAppModeCount", 1);
1024 size_t switch_count = command_line->GetSwitches().size();
1025 UMA_HISTOGRAM_COUNTS_100("Chrome.CommandLineFlagCount", switch_count);
1026 UMA_HISTOGRAM_COUNTS_100("Chrome.CommandLineUncommonFlagCount",
1027 switch_count - common_commands);
1029 // Kick off the process of saving the state (so the uptime numbers keep
1030 // getting updated) every n minutes.
1031 ScheduleNextStateSave();
1035 void MetricsService::InitTaskGetHardwareClass(
1036 base::WeakPtr<MetricsService> self,
1037 base::MessageLoopProxy* target_loop) {
1038 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
1040 std::string hardware_class;
1041 #if defined(OS_CHROMEOS)
1042 chromeos::system::StatisticsProvider::GetInstance()->GetMachineStatistic(
1043 "hardware_class", &hardware_class);
1044 #endif // OS_CHROMEOS
1046 target_loop->PostTask(FROM_HERE,
1047 base::Bind(&MetricsService::OnInitTaskGotHardwareClass,
1048 self, hardware_class));
1051 void MetricsService::OnInitTaskGotHardwareClass(
1052 const std::string& hardware_class) {
1053 DCHECK_EQ(INIT_TASK_SCHEDULED, state_);
1054 hardware_class_ = hardware_class;
1056 #if defined(ENABLE_PLUGINS)
1057 // Start the next part of the init task: loading plugin information.
1058 PluginService::GetInstance()->GetPlugins(
1059 base::Bind(&MetricsService::OnInitTaskGotPluginInfo,
1060 self_ptr_factory_.GetWeakPtr()));
1062 std::vector<content::WebPluginInfo> plugin_list_empty;
1063 OnInitTaskGotPluginInfo(plugin_list_empty);
1064 #endif // defined(ENABLE_PLUGINS)
1067 void MetricsService::OnInitTaskGotPluginInfo(
1068 const std::vector<content::WebPluginInfo>& plugins) {
1069 DCHECK_EQ(INIT_TASK_SCHEDULED, state_);
1072 // Schedules a task on a blocking pool thread to gather Google Update
1073 // statistics (requires Registry reads).
1074 BrowserThread::PostBlockingPoolTask(
1076 base::Bind(&MetricsService::InitTaskGetGoogleUpdateData,
1077 self_ptr_factory_.GetWeakPtr(),
1078 base::MessageLoop::current()->message_loop_proxy()));
1082 void MetricsService::InitTaskGetGoogleUpdateData(
1083 base::WeakPtr<MetricsService> self,
1084 base::MessageLoopProxy* target_loop) {
1085 GoogleUpdateMetrics google_update_metrics;
1087 #if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
1088 const bool system_install = GoogleUpdateSettings::IsSystemInstall();
1090 google_update_metrics.is_system_install = system_install;
1091 google_update_metrics.last_started_au =
1092 GoogleUpdateSettings::GetGoogleUpdateLastStartedAU(system_install);
1093 google_update_metrics.last_checked =
1094 GoogleUpdateSettings::GetGoogleUpdateLastChecked(system_install);
1095 GoogleUpdateSettings::GetUpdateDetailForGoogleUpdate(
1097 &google_update_metrics.google_update_data);
1098 GoogleUpdateSettings::GetUpdateDetail(
1100 &google_update_metrics.product_data);
1101 #endif // defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
1103 target_loop->PostTask(FROM_HERE,
1104 base::Bind(&MetricsService::OnInitTaskGotGoogleUpdateData,
1105 self, google_update_metrics));
1108 void MetricsService::OnInitTaskGotGoogleUpdateData(
1109 const GoogleUpdateMetrics& google_update_metrics) {
1110 DCHECK_EQ(INIT_TASK_SCHEDULED, state_);
1112 google_update_metrics_ = google_update_metrics;
1114 // Start the next part of the init task: fetching performance data. This will
1115 // call into |FinishedReceivingProfilerData()| when the task completes.
1116 chrome_browser_metrics::TrackingSynchronizer::FetchProfilerDataAsynchronously(
1117 self_ptr_factory_.GetWeakPtr());
1120 void MetricsService::OnUserAction(const std::string& action) {
1121 if (!CanLogNotification())
1124 log_manager_.current_log()->RecordUserAction(action.c_str());
1125 HandleIdleSinceLastTransmission(false);
1128 void MetricsService::ReceivedProfilerData(
1129 const tracked_objects::ProcessDataSnapshot& process_data,
1131 DCHECK_EQ(INIT_TASK_SCHEDULED, state_);
1133 // Upon the first callback, create the initial log so that we can immediately
1134 // save the profiler data.
1135 if (!initial_metrics_log_.get())
1136 initial_metrics_log_.reset(new MetricsLog(client_id_, session_id_));
1138 initial_metrics_log_->RecordProfilerData(process_data, process_type);
1141 void MetricsService::FinishedReceivingProfilerData() {
1142 DCHECK_EQ(INIT_TASK_SCHEDULED, state_);
1143 state_ = INIT_TASK_DONE;
1144 scheduler_->InitTaskComplete();
1147 base::TimeDelta MetricsService::GetIncrementalUptime(PrefService* pref) {
1148 base::TimeTicks now = base::TimeTicks::Now();
1149 // If this is the first call, init |last_updated_time_|.
1150 if (last_updated_time_.is_null())
1151 last_updated_time_ = now;
1152 const base::TimeDelta incremental_time = now - last_updated_time_;
1153 last_updated_time_ = now;
1155 const int64 incremental_time_secs = incremental_time.InSeconds();
1156 if (incremental_time_secs > 0) {
1157 int64 metrics_uptime = pref->GetInt64(prefs::kUninstallMetricsUptimeSec);
1158 metrics_uptime += incremental_time_secs;
1159 pref->SetInt64(prefs::kUninstallMetricsUptimeSec, metrics_uptime);
1162 return incremental_time;
1165 int MetricsService::GetLowEntropySource() {
1166 // Note that the default value for the low entropy source and the default pref
1167 // value are both kLowEntropySourceNotSet, which is used to identify if the
1168 // value has been set or not.
1169 if (low_entropy_source_ != kLowEntropySourceNotSet)
1170 return low_entropy_source_;
1172 PrefService* local_state = g_browser_process->local_state();
1173 const CommandLine* command_line(CommandLine::ForCurrentProcess());
1174 // Only try to load the value from prefs if the user did not request a reset.
1175 // Otherwise, skip to generating a new value.
1176 if (!command_line->HasSwitch(switches::kResetVariationState)) {
1177 int value = local_state->GetInteger(prefs::kMetricsLowEntropySource);
1178 // Old versions of the code would generate values in the range of [1, 8192],
1179 // before the range was switched to [0, 8191] and then to [0, 7999]. Map
1180 // 8192 to 0, so that the 0th bucket remains uniform, while re-generating
1181 // the low entropy source for old values in the [8000, 8191] range.
1184 // If the value is outside the [0, kMaxLowEntropySize) range, re-generate
1186 if (value >= 0 && value < kMaxLowEntropySize) {
1187 low_entropy_source_ = value;
1188 UMA_HISTOGRAM_BOOLEAN("UMA.GeneratedLowEntropySource", false);
1189 return low_entropy_source_;
1193 UMA_HISTOGRAM_BOOLEAN("UMA.GeneratedLowEntropySource", true);
1194 low_entropy_source_ = GenerateLowEntropySource();
1195 local_state->SetInteger(prefs::kMetricsLowEntropySource, low_entropy_source_);
1196 metrics::CachingPermutedEntropyProvider::ClearCache(local_state);
1198 return low_entropy_source_;
1202 std::string MetricsService::GenerateClientID() {
1203 return base::GenerateGUID();
1206 //------------------------------------------------------------------------------
1207 // State save methods
1209 void MetricsService::ScheduleNextStateSave() {
1210 state_saver_factory_.InvalidateWeakPtrs();
1212 base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
1213 base::Bind(&MetricsService::SaveLocalState,
1214 state_saver_factory_.GetWeakPtr()),
1215 base::TimeDelta::FromMinutes(kSaveStateIntervalMinutes));
1218 void MetricsService::SaveLocalState() {
1219 PrefService* pref = g_browser_process->local_state();
1225 RecordCurrentState(pref);
1227 // TODO(jar):110021 Does this run down the batteries????
1228 ScheduleNextStateSave();
1232 //------------------------------------------------------------------------------
1233 // Recording control methods
1235 void MetricsService::OpenNewLog() {
1236 DCHECK(!log_manager_.current_log());
1238 log_manager_.BeginLoggingWithLog(new MetricsLog(client_id_, session_id_),
1239 MetricsLog::ONGOING_LOG);
1240 if (state_ == INITIALIZED) {
1241 // We only need to schedule that run once.
1242 state_ = INIT_TASK_SCHEDULED;
1244 // Schedules a task on the file thread for execution of slower
1245 // initialization steps (such as plugin list generation) necessary
1246 // for sending the initial log. This avoids blocking the main UI
1248 BrowserThread::PostDelayedTask(
1249 BrowserThread::FILE,
1251 base::Bind(&MetricsService::InitTaskGetHardwareClass,
1252 self_ptr_factory_.GetWeakPtr(),
1253 base::MessageLoop::current()->message_loop_proxy()),
1254 base::TimeDelta::FromSeconds(kInitializationDelaySeconds));
1258 void MetricsService::CloseCurrentLog() {
1259 if (!log_manager_.current_log())
1262 // TODO(jar): Integrate bounds on log recording more consistently, so that we
1263 // can stop recording logs that are too big much sooner.
1264 if (log_manager_.current_log()->num_events() > kEventLimit) {
1265 UMA_HISTOGRAM_COUNTS("UMA.Discarded Log Events",
1266 log_manager_.current_log()->num_events());
1267 log_manager_.DiscardCurrentLog();
1268 OpenNewLog(); // Start trivial log to hold our histograms.
1271 // Adds to ongoing logs.
1272 log_manager_.current_log()->set_hardware_class(hardware_class_);
1274 // Put incremental data (histogram deltas, and realtime stats deltas) at the
1275 // end of all log transmissions (initial log handles this separately).
1276 // RecordIncrementalStabilityElements only exists on the derived
1277 // MetricsLog class.
1278 MetricsLog* current_log =
1279 static_cast<MetricsLog*>(log_manager_.current_log());
1280 DCHECK(current_log);
1281 std::vector<chrome_variations::ActiveGroupId> synthetic_trials;
1282 GetCurrentSyntheticFieldTrials(&synthetic_trials);
1283 current_log->RecordEnvironment(plugins_, google_update_metrics_,
1285 PrefService* pref = g_browser_process->local_state();
1286 current_log->RecordStabilityMetrics(GetIncrementalUptime(pref),
1287 MetricsLog::ONGOING_LOG);
1289 RecordCurrentHistograms();
1291 log_manager_.FinishCurrentLog();
1294 void MetricsService::PushPendingLogsToPersistentStorage() {
1295 if (state_ < SENDING_INITIAL_STABILITY_LOG)
1296 return; // We didn't and still don't have time to get plugin list etc.
1298 if (log_manager_.has_staged_log()) {
1299 // We may race here, and send second copy of the log later.
1300 MetricsLogManager::StoreType store_type;
1301 if (current_fetch_.get())
1302 store_type = MetricsLogManager::PROVISIONAL_STORE;
1304 store_type = MetricsLogManager::NORMAL_STORE;
1305 log_manager_.StoreStagedLogAsUnsent(store_type);
1307 DCHECK(!log_manager_.has_staged_log());
1309 log_manager_.PersistUnsentLogs();
1311 // If there was a staged and/or current log, then there is now at least one
1312 // log waiting to be uploaded.
1313 if (log_manager_.has_unsent_logs())
1314 state_ = SENDING_OLD_LOGS;
1317 //------------------------------------------------------------------------------
1318 // Transmission of logs methods
1320 void MetricsService::StartSchedulerIfNecessary() {
1321 // Never schedule cutting or uploading of logs in test mode.
1322 if (test_mode_active_)
1325 // Even if reporting is disabled, the scheduler is needed to trigger the
1326 // creation of the initial log, which must be done in order for any logs to be
1327 // persisted on shutdown or backgrounding.
1328 if (recording_active() &&
1329 (reporting_active() || state_ < SENDING_INITIAL_STABILITY_LOG)) {
1330 scheduler_->Start();
1334 void MetricsService::StartScheduledUpload() {
1335 // If we're getting no notifications, then the log won't have much in it, and
1336 // it's possible the computer is about to go to sleep, so don't upload and
1337 // stop the scheduler.
1338 // If recording has been turned off, the scheduler doesn't need to run.
1339 // If reporting is off, proceed if the initial log hasn't been created, since
1340 // that has to happen in order for logs to be cut and stored when persisting.
1341 // TODO(stuartmorgan): Call Stop() on the schedule when reporting and/or
1342 // recording are turned off instead of letting it fire and then aborting.
1343 if (idle_since_last_transmission_ ||
1344 !recording_active() ||
1345 (!reporting_active() && state_ >= SENDING_INITIAL_STABILITY_LOG)) {
1347 scheduler_->UploadCancelled();
1351 // If the callback was to upload an old log, but there no longer is one,
1352 // just report success back to the scheduler to begin the ongoing log
1354 // TODO(stuartmorgan): Consider removing the distinction between
1355 // SENDING_OLD_LOGS and SENDING_CURRENT_LOGS to simplify the state machine
1356 // now that the log upload flow is the same for both modes.
1357 if (state_ == SENDING_OLD_LOGS && !log_manager_.has_unsent_logs()) {
1358 state_ = SENDING_CURRENT_LOGS;
1359 scheduler_->UploadFinished(true /* healthy */, false /* no unsent logs */);
1362 // If there are unsent logs, send the next one. If not, start the asynchronous
1363 // process of finalizing the current log for upload.
1364 if (state_ == SENDING_OLD_LOGS) {
1365 DCHECK(log_manager_.has_unsent_logs());
1366 log_manager_.StageNextLogForUpload();
1369 StartFinalLogInfoCollection();
1373 void MetricsService::StartFinalLogInfoCollection() {
1374 // Begin the multi-step process of collecting memory usage histograms:
1375 // First spawn a task to collect the memory details; when that task is
1376 // finished, it will call OnMemoryDetailCollectionDone. That will in turn
1377 // call HistogramSynchronization to collect histograms from all renderers and
1378 // then call OnHistogramSynchronizationDone to continue processing.
1379 DCHECK(!waiting_for_asynchronous_reporting_step_);
1380 waiting_for_asynchronous_reporting_step_ = true;
1382 base::Closure callback =
1383 base::Bind(&MetricsService::OnMemoryDetailCollectionDone,
1384 self_ptr_factory_.GetWeakPtr());
1386 scoped_refptr<MetricsMemoryDetails> details(
1387 new MetricsMemoryDetails(callback));
1388 details->StartFetch(MemoryDetails::UPDATE_USER_METRICS);
1390 // Collect WebCore cache information to put into a histogram.
1391 for (content::RenderProcessHost::iterator i(
1392 content::RenderProcessHost::AllHostsIterator());
1393 !i.IsAtEnd(); i.Advance())
1394 i.GetCurrentValue()->Send(new ChromeViewMsg_GetCacheResourceStats());
1397 void MetricsService::OnMemoryDetailCollectionDone() {
1398 DCHECK(IsSingleThreaded());
1399 // This function should only be called as the callback from an ansynchronous
1401 DCHECK(waiting_for_asynchronous_reporting_step_);
1403 // Create a callback_task for OnHistogramSynchronizationDone.
1404 base::Closure callback = base::Bind(
1405 &MetricsService::OnHistogramSynchronizationDone,
1406 self_ptr_factory_.GetWeakPtr());
1408 base::TimeDelta timeout =
1409 base::TimeDelta::FromMilliseconds(kMaxHistogramGatheringWaitDuration);
1411 DCHECK_EQ(num_async_histogram_fetches_in_progress_, 0);
1413 #if defined(OS_ANDROID)
1414 // Android has no service process.
1415 num_async_histogram_fetches_in_progress_ = 1;
1417 num_async_histogram_fetches_in_progress_ = 2;
1418 // Run requests to service and content in parallel.
1419 if (!ServiceProcessControl::GetInstance()->GetHistograms(callback, timeout)) {
1420 // Assume |num_async_histogram_fetches_in_progress_| is not changed by
1421 // |GetHistograms()|.
1422 DCHECK_EQ(num_async_histogram_fetches_in_progress_, 2);
1423 // Assign |num_async_histogram_fetches_in_progress_| above and decrement it
1424 // here to make code work even if |GetHistograms()| fired |callback|.
1425 --num_async_histogram_fetches_in_progress_;
1427 #endif // OS_ANDROID
1429 // Set up the callback to task to call after we receive histograms from all
1430 // child processes. Wait time specifies how long to wait before absolutely
1431 // calling us back on the task.
1432 content::FetchHistogramsAsynchronously(base::MessageLoop::current(), callback,
1436 void MetricsService::OnHistogramSynchronizationDone() {
1437 DCHECK(IsSingleThreaded());
1438 // This function should only be called as the callback from an ansynchronous
1440 DCHECK(waiting_for_asynchronous_reporting_step_);
1441 DCHECK_GT(num_async_histogram_fetches_in_progress_, 0);
1443 // Check if all expected requests finished.
1444 if (--num_async_histogram_fetches_in_progress_ > 0)
1447 waiting_for_asynchronous_reporting_step_ = false;
1448 OnFinalLogInfoCollectionDone();
1451 void MetricsService::OnFinalLogInfoCollectionDone() {
1452 // If somehow there is a fetch in progress, we return and hope things work
1453 // out. The scheduler isn't informed since if this happens, the scheduler
1454 // will get a response from the upload.
1455 DCHECK(!current_fetch_.get());
1456 if (current_fetch_.get())
1459 // Abort if metrics were turned off during the final info gathering.
1460 if (!recording_active()) {
1462 scheduler_->UploadCancelled();
1468 // If logs shouldn't be uploaded, stop here. It's important that this check
1469 // be after StageNewLog(), otherwise the previous logs will never be loaded,
1470 // and thus the open log won't be persisted.
1471 // TODO(stuartmorgan): This is unnecessarily complicated; restructure loading
1472 // of previous logs to not require running part of the upload logic.
1473 // http://crbug.com/157337
1474 if (!reporting_active()) {
1476 scheduler_->UploadCancelled();
1483 void MetricsService::StageNewLog() {
1484 if (log_manager_.has_staged_log())
1489 case INIT_TASK_SCHEDULED: // We should be further along by now.
1493 case INIT_TASK_DONE:
1494 if (has_initial_stability_log_) {
1495 // There's an initial stability log, ready to send.
1496 log_manager_.StageNextLogForUpload();
1497 has_initial_stability_log_ = false;
1498 // Note: No need to call LoadPersistedUnsentLogs() here because unsent
1499 // logs have already been loaded by PrepareInitialStabilityLog().
1500 state_ = SENDING_INITIAL_STABILITY_LOG;
1502 // TODO(asvitkine): When the field trial is removed, the |log_type|
1503 // arg should be removed and PrepareInitialMetricsLog() should always
1504 // use ONGOING_LOG. Use INITIAL_LOG only to match to the old behavior
1505 // when the field trial is off.
1506 MetricsLog::LogType log_type = SendSeparateInitialStabilityLog() ?
1507 MetricsLog::ONGOING_LOG : MetricsLog::INITIAL_LOG;
1508 PrepareInitialMetricsLog(log_type);
1509 // Load unsent logs (if any) from local state.
1510 log_manager_.LoadPersistedUnsentLogs();
1511 state_ = SENDING_INITIAL_METRICS_LOG;
1515 case SENDING_OLD_LOGS:
1516 NOTREACHED(); // Shouldn't be staging a new log during old log sending.
1519 case SENDING_CURRENT_LOGS:
1522 log_manager_.StageNextLogForUpload();
1530 DCHECK(log_manager_.has_staged_log());
1533 void MetricsService::PrepareInitialStabilityLog() {
1534 DCHECK_EQ(INITIALIZED, state_);
1535 PrefService* pref = g_browser_process->local_state();
1536 DCHECK_NE(0, pref->GetInteger(prefs::kStabilityCrashCount));
1538 scoped_ptr<MetricsLog> initial_stability_log(
1539 new MetricsLog(client_id_, session_id_));
1540 if (!initial_stability_log->LoadSavedEnvironmentFromPrefs())
1542 initial_stability_log->RecordStabilityMetrics(base::TimeDelta(),
1543 MetricsLog::INITIAL_LOG);
1544 log_manager_.LoadPersistedUnsentLogs();
1546 log_manager_.PauseCurrentLog();
1547 log_manager_.BeginLoggingWithLog(initial_stability_log.release(),
1548 MetricsLog::INITIAL_LOG);
1549 #if defined(OS_ANDROID)
1550 ConvertAndroidStabilityPrefsToHistograms(pref);
1551 RecordCurrentStabilityHistograms();
1552 #endif // defined(OS_ANDROID)
1553 log_manager_.FinishCurrentLog();
1554 log_manager_.ResumePausedLog();
1556 // Store unsent logs, including the stability log that was just saved, so
1557 // that they're not lost in case of a crash before upload time.
1558 log_manager_.PersistUnsentLogs();
1560 has_initial_stability_log_ = true;
1563 void MetricsService::PrepareInitialMetricsLog(MetricsLog::LogType log_type) {
1564 DCHECK(state_ == INIT_TASK_DONE || state_ == SENDING_INITIAL_STABILITY_LOG);
1565 initial_metrics_log_->set_hardware_class(hardware_class_);
1567 std::vector<chrome_variations::ActiveGroupId> synthetic_trials;
1568 GetCurrentSyntheticFieldTrials(&synthetic_trials);
1569 initial_metrics_log_->RecordEnvironment(plugins_, google_update_metrics_,
1571 PrefService* pref = g_browser_process->local_state();
1572 initial_metrics_log_->RecordStabilityMetrics(GetIncrementalUptime(pref),
1575 // Histograms only get written to the current log, so make the new log current
1576 // before writing them.
1577 log_manager_.PauseCurrentLog();
1578 log_manager_.BeginLoggingWithLog(initial_metrics_log_.release(), log_type);
1579 #if defined(OS_ANDROID)
1580 ConvertAndroidStabilityPrefsToHistograms(pref);
1581 #endif // defined(OS_ANDROID)
1582 RecordCurrentHistograms();
1583 log_manager_.FinishCurrentLog();
1584 log_manager_.ResumePausedLog();
1586 DCHECK(!log_manager_.has_staged_log());
1587 log_manager_.StageNextLogForUpload();
1590 void MetricsService::SendStagedLog() {
1591 DCHECK(log_manager_.has_staged_log());
1593 PrepareFetchWithStagedLog();
1595 bool upload_created = (current_fetch_.get() != NULL);
1596 UMA_HISTOGRAM_BOOLEAN("UMA.UploadCreation", upload_created);
1597 if (!upload_created) {
1598 // Compression failed, and log discarded :-/.
1599 // Skip this upload and hope things work out next time.
1600 log_manager_.DiscardStagedLog();
1601 scheduler_->UploadCancelled();
1605 DCHECK(!waiting_for_asynchronous_reporting_step_);
1606 waiting_for_asynchronous_reporting_step_ = true;
1608 current_fetch_->Start();
1610 HandleIdleSinceLastTransmission(true);
1613 void MetricsService::PrepareFetchWithStagedLog() {
1614 DCHECK(log_manager_.has_staged_log());
1616 // Prepare the protobuf version.
1617 DCHECK(!current_fetch_.get());
1618 if (log_manager_.has_staged_log()) {
1619 current_fetch_.reset(net::URLFetcher::Create(
1620 GURL(kServerUrl), net::URLFetcher::POST, this));
1621 current_fetch_->SetRequestContext(
1622 g_browser_process->system_request_context());
1624 std::string log_text = log_manager_.staged_log_text();
1625 std::string compressed_log_text;
1626 bool compression_successful = chrome::GzipCompress(log_text,
1627 &compressed_log_text);
1628 DCHECK(compression_successful);
1629 if (compression_successful) {
1630 current_fetch_->SetUploadData(kMimeType, compressed_log_text);
1631 // Tell the server that we're uploading gzipped protobufs.
1632 current_fetch_->SetExtraRequestHeaders("content-encoding: gzip");
1633 const std::string hash =
1634 base::HexEncode(log_manager_.staged_log_hash().data(),
1635 log_manager_.staged_log_hash().size());
1636 DCHECK(!hash.empty());
1637 current_fetch_->AddExtraRequestHeader("X-Chrome-UMA-Log-SHA1: " + hash);
1638 UMA_HISTOGRAM_PERCENTAGE(
1639 "UMA.ProtoCompressionRatio",
1640 100 * compressed_log_text.size() / log_text.size());
1641 UMA_HISTOGRAM_CUSTOM_COUNTS(
1642 "UMA.ProtoGzippedKBSaved",
1643 (log_text.size() - compressed_log_text.size()) / 1024,
1647 // We already drop cookies server-side, but we might as well strip them out
1648 // client-side as well.
1649 current_fetch_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES |
1650 net::LOAD_DO_NOT_SEND_COOKIES);
1654 void MetricsService::OnURLFetchComplete(const net::URLFetcher* source) {
1655 DCHECK(waiting_for_asynchronous_reporting_step_);
1657 // We're not allowed to re-use the existing |URLFetcher|s, so free them here.
1658 // Note however that |source| is aliased to the fetcher, so we should be
1659 // careful not to delete it too early.
1660 DCHECK_EQ(current_fetch_.get(), source);
1661 scoped_ptr<net::URLFetcher> s(current_fetch_.Pass());
1663 int response_code = source->GetResponseCode();
1665 // Log a histogram to track response success vs. failure rates.
1666 UMA_HISTOGRAM_ENUMERATION("UMA.UploadResponseStatus.Protobuf",
1667 ResponseCodeToStatus(response_code),
1668 NUM_RESPONSE_STATUSES);
1670 // If the upload was provisionally stored, drop it now that the upload is
1671 // known to have gone through.
1672 log_manager_.DiscardLastProvisionalStore();
1674 bool upload_succeeded = response_code == 200;
1676 // Provide boolean for error recovery (allow us to ignore response_code).
1677 bool discard_log = false;
1678 const size_t log_size = log_manager_.staged_log_text().length();
1679 if (!upload_succeeded && log_size > kUploadLogAvoidRetransmitSize) {
1680 UMA_HISTOGRAM_COUNTS("UMA.Large Rejected Log was Discarded",
1681 static_cast<int>(log_size));
1683 } else if (response_code == 400) {
1684 // Bad syntax. Retransmission won't work.
1688 if (upload_succeeded || discard_log)
1689 log_manager_.DiscardStagedLog();
1691 waiting_for_asynchronous_reporting_step_ = false;
1693 if (!log_manager_.has_staged_log()) {
1695 case SENDING_INITIAL_STABILITY_LOG:
1696 // Store the updated list to disk now that the removed log is uploaded.
1697 log_manager_.PersistUnsentLogs();
1698 PrepareInitialMetricsLog(MetricsLog::ONGOING_LOG);
1700 state_ = SENDING_INITIAL_METRICS_LOG;
1703 case SENDING_INITIAL_METRICS_LOG:
1704 // The initial metrics log never gets persisted to local state, so it's
1705 // not necessary to call log_manager_.PersistUnsentLogs() here.
1706 // TODO(asvitkine): It should be persisted like the initial stability
1707 // log and old unsent logs. http://crbug.com/328417
1708 state_ = log_manager_.has_unsent_logs() ? SENDING_OLD_LOGS
1709 : SENDING_CURRENT_LOGS;
1712 case SENDING_OLD_LOGS:
1713 // Store the updated list to disk now that the removed log is uploaded.
1714 log_manager_.PersistUnsentLogs();
1715 if (!log_manager_.has_unsent_logs())
1716 state_ = SENDING_CURRENT_LOGS;
1719 case SENDING_CURRENT_LOGS:
1727 if (log_manager_.has_unsent_logs())
1728 DCHECK_LT(state_, SENDING_CURRENT_LOGS);
1731 // Error 400 indicates a problem with the log, not with the server, so
1732 // don't consider that a sign that the server is in trouble.
1733 bool server_is_healthy = upload_succeeded || response_code == 400;
1734 // Don't notify the scheduler that the upload is finished if we've only sent
1735 // the initial stability log, but not yet the initial metrics log (treat the
1736 // two as a single unit of work as far as the scheduler is concerned).
1737 if (state_ != SENDING_INITIAL_METRICS_LOG) {
1738 scheduler_->UploadFinished(server_is_healthy,
1739 log_manager_.has_unsent_logs());
1742 // Collect network stats if UMA upload succeeded.
1743 IOThread* io_thread = g_browser_process->io_thread();
1744 if (server_is_healthy && io_thread) {
1745 chrome_browser_net::CollectNetworkStats(network_stats_server_, io_thread);
1746 chrome_browser_net::CollectPipeliningCapabilityStatsOnUIThread(
1747 http_pipelining_test_server_, io_thread);
1749 chrome::CollectTimeTicksStats();
1754 void MetricsService::IncrementPrefValue(const char* path) {
1755 PrefService* pref = g_browser_process->local_state();
1757 int value = pref->GetInteger(path);
1758 pref->SetInteger(path, value + 1);
1761 void MetricsService::IncrementLongPrefsValue(const char* path) {
1762 PrefService* pref = g_browser_process->local_state();
1764 int64 value = pref->GetInt64(path);
1765 pref->SetInt64(path, value + 1);
1768 void MetricsService::LogLoadStarted(content::WebContents* web_contents) {
1769 content::RecordAction(base::UserMetricsAction("PageLoad"));
1770 HISTOGRAM_ENUMERATION("Chrome.UmaPageloadCounter", 1, 2);
1771 IncrementPrefValue(prefs::kStabilityPageLoadCount);
1772 IncrementLongPrefsValue(prefs::kUninstallMetricsPageLoadCount);
1773 // We need to save the prefs, as page load count is a critical stat, and it
1774 // might be lost due to a crash :-(.
1777 void MetricsService::LogRendererCrash(content::RenderProcessHost* host,
1778 base::TerminationStatus status,
1780 bool was_extension_process =
1781 extensions::ProcessMap::Get(host->GetBrowserContext())
1782 ->Contains(host->GetID());
1783 if (status == base::TERMINATION_STATUS_PROCESS_CRASHED ||
1784 status == base::TERMINATION_STATUS_ABNORMAL_TERMINATION) {
1785 if (was_extension_process) {
1786 IncrementPrefValue(prefs::kStabilityExtensionRendererCrashCount);
1788 UMA_HISTOGRAM_SPARSE_SLOWLY("CrashExitCodes.Extension",
1789 MapCrashExitCodeForHistogram(exit_code));
1791 IncrementPrefValue(prefs::kStabilityRendererCrashCount);
1793 UMA_HISTOGRAM_SPARSE_SLOWLY("CrashExitCodes.Renderer",
1794 MapCrashExitCodeForHistogram(exit_code));
1797 UMA_HISTOGRAM_PERCENTAGE("BrowserRenderProcessHost.ChildCrashes",
1798 was_extension_process ? 2 : 1);
1799 } else if (status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED) {
1800 UMA_HISTOGRAM_PERCENTAGE("BrowserRenderProcessHost.ChildKills",
1801 was_extension_process ? 2 : 1);
1802 } else if (status == base::TERMINATION_STATUS_STILL_RUNNING) {
1803 UMA_HISTOGRAM_PERCENTAGE("BrowserRenderProcessHost.DisconnectedAlive",
1804 was_extension_process ? 2 : 1);
1808 void MetricsService::LogRendererHang() {
1809 IncrementPrefValue(prefs::kStabilityRendererHangCount);
1812 bool MetricsService::UmaMetricsProperlyShutdown() {
1813 CHECK(clean_shutdown_status_ == CLEANLY_SHUTDOWN ||
1814 clean_shutdown_status_ == NEED_TO_SHUTDOWN);
1815 return clean_shutdown_status_ == CLEANLY_SHUTDOWN;
1818 void MetricsService::RegisterSyntheticFieldTrial(
1819 const SyntheticTrialGroup& trial) {
1820 for (size_t i = 0; i < synthetic_trial_groups_.size(); ++i) {
1821 if (synthetic_trial_groups_[i].id.name == trial.id.name) {
1822 if (synthetic_trial_groups_[i].id.group != trial.id.group) {
1823 synthetic_trial_groups_[i].id.group = trial.id.group;
1824 synthetic_trial_groups_[i].start_time = trial.start_time;
1830 SyntheticTrialGroup trial_group(
1831 trial.id.name, trial.id.group, base::TimeTicks::Now());
1832 synthetic_trial_groups_.push_back(trial_group);
1835 void MetricsService::GetCurrentSyntheticFieldTrials(
1836 std::vector<chrome_variations::ActiveGroupId>* synthetic_trials) {
1837 DCHECK(synthetic_trials);
1838 synthetic_trials->clear();
1839 const MetricsLog* current_log =
1840 static_cast<const MetricsLog*>(log_manager_.current_log());
1841 for (size_t i = 0; i < synthetic_trial_groups_.size(); ++i) {
1842 if (synthetic_trial_groups_[i].start_time <= current_log->creation_time())
1843 synthetic_trials->push_back(synthetic_trial_groups_[i].id);
1847 void MetricsService::LogCleanShutdown() {
1848 // Redundant hack to write pref ASAP.
1849 MarkAppCleanShutdownAndCommit();
1851 // Redundant setting to assure that we always reset this value at shutdown
1852 // (and that we don't use some alternate path, and not call LogCleanShutdown).
1853 clean_shutdown_status_ = CLEANLY_SHUTDOWN;
1855 RecordBooleanPrefValue(prefs::kStabilityExitedCleanly, true);
1856 PrefService* pref = g_browser_process->local_state();
1857 pref->SetInteger(prefs::kStabilityExecutionPhase,
1858 MetricsService::SHUTDOWN_COMPLETE);
1861 #if defined(OS_CHROMEOS)
1862 void MetricsService::LogChromeOSCrash(const std::string &crash_type) {
1863 if (crash_type == "user")
1864 IncrementPrefValue(prefs::kStabilityOtherUserCrashCount);
1865 else if (crash_type == "kernel")
1866 IncrementPrefValue(prefs::kStabilityKernelCrashCount);
1867 else if (crash_type == "uncleanshutdown")
1868 IncrementPrefValue(prefs::kStabilitySystemUncleanShutdownCount);
1870 NOTREACHED() << "Unexpected Chrome OS crash type " << crash_type;
1871 // Wake up metrics logs sending if necessary now that new
1872 // log data is available.
1873 HandleIdleSinceLastTransmission(false);
1875 #endif // OS_CHROMEOS
1877 void MetricsService::LogPluginLoadingError(const base::FilePath& plugin_path) {
1878 content::WebPluginInfo plugin;
1880 content::PluginService::GetInstance()->GetPluginInfoByPath(plugin_path,
1883 ChildProcessStats& stats = child_process_stats_buffer_[plugin.name];
1884 // Initialize the type if this entry is new.
1885 if (stats.process_type == content::PROCESS_TYPE_UNKNOWN) {
1886 // The plug-in process might not actually of type PLUGIN (which means
1887 // NPAPI), but we only care that it is *a* plug-in process.
1888 stats.process_type = content::PROCESS_TYPE_PLUGIN;
1890 DCHECK(IsPluginProcess(stats.process_type));
1892 stats.loading_errors++;
1895 MetricsService::ChildProcessStats& MetricsService::GetChildProcessStats(
1896 const content::ChildProcessData& data) {
1897 const base::string16& child_name = data.name;
1898 if (!ContainsKey(child_process_stats_buffer_, child_name)) {
1899 child_process_stats_buffer_[child_name] =
1900 ChildProcessStats(data.process_type);
1902 return child_process_stats_buffer_[child_name];
1905 void MetricsService::RecordPluginChanges(PrefService* pref) {
1906 ListPrefUpdate update(pref, prefs::kStabilityPluginStats);
1907 base::ListValue* plugins = update.Get();
1910 for (base::ListValue::iterator value_iter = plugins->begin();
1911 value_iter != plugins->end(); ++value_iter) {
1912 if (!(*value_iter)->IsType(base::Value::TYPE_DICTIONARY)) {
1917 base::DictionaryValue* plugin_dict =
1918 static_cast<base::DictionaryValue*>(*value_iter);
1919 std::string plugin_name;
1920 plugin_dict->GetString(prefs::kStabilityPluginName, &plugin_name);
1921 if (plugin_name.empty()) {
1926 // TODO(viettrungluu): remove conversions
1927 base::string16 name16 = base::UTF8ToUTF16(plugin_name);
1928 if (child_process_stats_buffer_.find(name16) ==
1929 child_process_stats_buffer_.end()) {
1933 ChildProcessStats stats = child_process_stats_buffer_[name16];
1934 if (stats.process_launches) {
1936 plugin_dict->GetInteger(prefs::kStabilityPluginLaunches, &launches);
1937 launches += stats.process_launches;
1938 plugin_dict->SetInteger(prefs::kStabilityPluginLaunches, launches);
1940 if (stats.process_crashes) {
1942 plugin_dict->GetInteger(prefs::kStabilityPluginCrashes, &crashes);
1943 crashes += stats.process_crashes;
1944 plugin_dict->SetInteger(prefs::kStabilityPluginCrashes, crashes);
1946 if (stats.instances) {
1948 plugin_dict->GetInteger(prefs::kStabilityPluginInstances, &instances);
1949 instances += stats.instances;
1950 plugin_dict->SetInteger(prefs::kStabilityPluginInstances, instances);
1952 if (stats.loading_errors) {
1953 int loading_errors = 0;
1954 plugin_dict->GetInteger(prefs::kStabilityPluginLoadingErrors,
1956 loading_errors += stats.loading_errors;
1957 plugin_dict->SetInteger(prefs::kStabilityPluginLoadingErrors,
1961 child_process_stats_buffer_.erase(name16);
1964 // Now go through and add dictionaries for plugins that didn't already have
1965 // reports in Local State.
1966 for (std::map<base::string16, ChildProcessStats>::iterator cache_iter =
1967 child_process_stats_buffer_.begin();
1968 cache_iter != child_process_stats_buffer_.end(); ++cache_iter) {
1969 ChildProcessStats stats = cache_iter->second;
1971 // Insert only plugins information into the plugins list.
1972 if (!IsPluginProcess(stats.process_type))
1975 // TODO(viettrungluu): remove conversion
1976 std::string plugin_name = base::UTF16ToUTF8(cache_iter->first);
1978 base::DictionaryValue* plugin_dict = new base::DictionaryValue;
1980 plugin_dict->SetString(prefs::kStabilityPluginName, plugin_name);
1981 plugin_dict->SetInteger(prefs::kStabilityPluginLaunches,
1982 stats.process_launches);
1983 plugin_dict->SetInteger(prefs::kStabilityPluginCrashes,
1984 stats.process_crashes);
1985 plugin_dict->SetInteger(prefs::kStabilityPluginInstances,
1987 plugin_dict->SetInteger(prefs::kStabilityPluginLoadingErrors,
1988 stats.loading_errors);
1989 plugins->Append(plugin_dict);
1991 child_process_stats_buffer_.clear();
1994 bool MetricsService::CanLogNotification() {
1995 // We simply don't log anything to UMA if there is a single incognito
1996 // session visible. The problem is that we always notify using the orginal
1997 // profile in order to simplify notification processing.
1998 return !chrome::IsOffTheRecordSessionActive();
2001 void MetricsService::RecordBooleanPrefValue(const char* path, bool value) {
2002 DCHECK(IsSingleThreaded());
2004 PrefService* pref = g_browser_process->local_state();
2007 pref->SetBoolean(path, value);
2008 RecordCurrentState(pref);
2011 void MetricsService::RecordCurrentState(PrefService* pref) {
2012 pref->SetInt64(prefs::kStabilityLastTimestampSec, Time::Now().ToTimeT());
2014 RecordPluginChanges(pref);
2018 bool MetricsService::IsPluginProcess(int process_type) {
2019 return (process_type == content::PROCESS_TYPE_PLUGIN ||
2020 process_type == content::PROCESS_TYPE_PPAPI_PLUGIN ||
2021 process_type == content::PROCESS_TYPE_PPAPI_BROKER);
2024 #if defined(OS_CHROMEOS)
2025 void MetricsService::StartExternalMetrics() {
2026 external_metrics_ = new chromeos::ExternalMetrics;
2027 external_metrics_->Start();
2032 bool MetricsServiceHelper::IsMetricsReportingEnabled() {
2033 bool result = false;
2034 const PrefService* local_state = g_browser_process->local_state();
2036 const PrefService::Preference* uma_pref =
2037 local_state->FindPreference(prefs::kMetricsReportingEnabled);
2039 bool success = uma_pref->GetValue()->GetAsBoolean(&result);