Disable TabDragController tests that fail with a real compositor.
[chromium-blink-merge.git] / chrome / browser / metrics / metrics_service.cc
blobc05dbbc19bc63b90e905634b219bd3f12709fe45
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.
7 //
8 // OVERVIEW
9 //
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
77 // are:
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
91 // initial log.
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
98 // completion.
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
127 // (see next state).
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
132 // started.
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
144 // state.
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
149 // will be sent.
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"
166 #include <algorithm>
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"
232 #endif
234 #if defined(OS_CHROMEOS)
235 #include "chrome/browser/chromeos/external_metrics.h"
236 #include "chromeos/system/statistics_provider.h"
237 #endif
239 #if defined(OS_WIN)
240 #include <windows.h> // Needed for STATUS_* codes
241 #include "base/win/registry.h"
242 #endif
244 #if !defined(OS_ANDROID)
245 #include "chrome/browser/service_process/service_process_control.h"
246 #endif
248 using base::Time;
249 using content::BrowserThread;
250 using content::ChildProcessData;
251 using content::LoadNotificationDetails;
252 using content::PluginService;
254 namespace {
256 // Check to see that we're being called on only one thread.
257 bool IsSingleThreaded() {
258 static base::PlatformThreadId thread_id = 0;
259 if (!thread_id)
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;
272 #else
273 const int kInitializationDelaySeconds = 30;
274 #endif
276 // This specifies the amount of time to wait for all renderers to send their
277 // data.
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 {
293 UNKNOWN_FAILURE,
294 SUCCESS,
295 BAD_REQUEST, // Invalid syntax or log too large.
296 NO_RESPONSE,
297 NUM_RESPONSE_STATUSES
300 ResponseStatus ResponseCodeToStatus(int response_code) {
301 switch (response_code) {
302 case 200:
303 return SUCCESS;
304 case 400:
305 return BAD_REQUEST;
306 case net::URLFetcher::RESPONSE_CODE_INVALID:
307 return NO_RESPONSE;
308 default:
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
323 // activities.
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) {
331 #if defined(OS_WIN)
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.
337 #endif
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";
356 } // namespace
359 SyntheticTrialGroup::SyntheticTrialGroup(uint32 trial,
360 uint32 group,
361 base::TimeTicks start)
362 : start_time(start) {
363 id.name = trial;
364 id.group = group;
367 SyntheticTrialGroup::~SyntheticTrialGroup() {
370 // static
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 {
382 public:
383 explicit ChildProcessStats(int process_type)
384 : process_launches(0),
385 process_crashes(0),
386 instances(0),
387 loading_errors(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.
392 ChildProcessStats()
393 : process_launches(0),
394 process_crashes(0),
395 instances(0),
396 loading_errors(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
403 int process_crashes;
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
407 // load.
408 int instances;
410 // The number of times there was an error loading an instance of this child
411 // process.
412 int loading_errors;
414 int process_type;
417 // Handles asynchronous fetching of memory details.
418 // Will run the provided task after finished.
419 class MetricsMemoryDetails : public MemoryDetails {
420 public:
421 explicit MetricsMemoryDetails(const base::Closure& callback)
422 : callback_(callback) {}
424 virtual void OnDetailsAvailable() OVERRIDE {
425 base::MessageLoop::current()->PostTask(FROM_HERE, callback_);
428 private:
429 virtual ~MetricsMemoryDetails() {}
431 base::Closure callback_;
432 DISALLOW_COPY_AND_ASSIGN(MetricsMemoryDetails);
435 // static
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,
472 std::string());
473 registry->RegisterStringPref(prefs::kStabilitySavedSystemProfileHash,
474 std::string());
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);
487 // static
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),
519 state_(INITIALIZED),
520 has_initial_stability_log_(false),
521 low_entropy_source_(kLowEntropySourceNotSet),
522 idle_since_last_transmission_(false),
523 session_id_(-1),
524 next_window_id_(0),
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() {
539 DisableRecording();
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);
555 EnableRecording();
556 EnableReporting();
559 void MetricsService::StartRecordingForTests() {
560 test_mode_active_ = true;
561 EnableRecording();
562 DisableReporting();
565 void MetricsService::Stop() {
566 HandleIdleSinceLastTransmission(false);
567 DisableReporting();
568 DisableRecording();
571 void MetricsService::EnableReporting() {
572 if (reporting_active_)
573 return;
574 reporting_active_ = true;
575 StartSchedulerIfNecessary();
578 void MetricsService::DisableReporting() {
579 reporting_active_ = false;
582 std::string MetricsService::GetClientId() {
583 return client_id_;
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
590 // entropy source.
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));
618 #else
619 return scoped_ptr<const base::FieldTrial::EntropyProvider>(
620 new metrics::PermutedEntropyProvider(low_entropy_source_value,
621 kMaxLowEntropySize));
622 #endif
625 void MetricsService::ForceClientIdCreation() {
626 if (!client_id_.empty())
627 return;
628 PrefService* pref = g_browser_process->local_state();
629 client_id_ = pref->GetString(prefs::kMetricsClientID);
630 if (!client_id_.empty())
631 return;
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_)
645 return;
646 recording_active_ = true;
648 ForceClientIdCreation();
649 crash_keys::SetClientID(client_id_);
650 if (!log_manager_.current_log())
651 OpenNewLog();
653 SetUpNotifications(&registrar_, 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_)
664 return;
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_;
683 // static
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())
733 return;
735 switch (type) {
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.
742 break;
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);
749 break;
752 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: {
753 content::RenderProcessHost::RendererClosedDetails* process_details =
754 content::Details<
755 content::RenderProcessHost::RendererClosedDetails>(
756 details).ptr();
757 content::RenderProcessHost* host =
758 content::Source<content::RenderProcessHost>(source).ptr();
759 LogRendererCrash(
760 host, process_details->status, process_details->exit_code);
762 break;
764 case content::NOTIFICATION_RENDER_WIDGET_HOST_HANG:
765 LogRendererHang();
766 break;
768 case chrome::NOTIFICATION_OMNIBOX_OPENED_URL: {
769 MetricsLog* current_log =
770 static_cast<MetricsLog*>(log_manager_.current_log());
771 DCHECK(current_log);
772 current_log->RecordOmniboxOpenedURL(
773 *content::Details<OmniboxLog>(details).ptr());
774 break;
777 default:
778 NOTREACHED();
779 break;
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
788 // again.
789 if (!in_idle && idle_since_last_transmission_)
790 StartSchedulerIfNecessary();
791 idle_since_last_transmission_ = in_idle;
794 void MetricsService::RecordStartOfSessionEnd() {
795 LogCleanShutdown();
796 RecordBooleanPrefValue(prefs::kStabilitySessionEndCompleted, false);
799 void MetricsService::RecordCompletedSessionEnd() {
800 LogCleanShutdown();
801 RecordBooleanPrefValue(prefs::kStabilitySessionEndCompleted, true);
804 #if defined(OS_ANDROID) || defined(OS_IOS)
805 void MetricsService::OnAppEnterBackground() {
806 scheduler_->Stop();
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.
819 OpenNewLog();
823 void MetricsService::OnAppEnterForeground() {
824 PrefService* pref = g_browser_process->local_state();
825 pref->SetBoolean(prefs::kStabilityExitedCleanly, false);
827 StartSchedulerIfNecessary();
829 #else
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)
838 // static
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) {
846 if (!success)
847 IncrementPrefValue(prefs::kStabilityBreakpadRegistrationFail);
848 else
849 IncrementPrefValue(prefs::kStabilityBreakpadRegistrationSuccess);
852 void MetricsService::RecordBreakpadHasDebugger(bool has_debugger) {
853 if (!has_debugger)
854 IncrementPrefValue(prefs::kStabilityDebuggerNotPresent);
855 else
856 IncrementPrefValue(prefs::kStabilityDebuggerPresent);
859 #if defined(OS_WIN)
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) {
866 return;
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.
880 base::string16 name;
881 DWORD value = 0;
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);
889 if (value == 0)
890 ++dumps_with_no_crash;
891 else
892 ++dumps_with_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 //------------------------------------------------------------------------------
912 // private methods
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;
923 #else
924 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
925 network_stats_server_ = dist->GetNetworkStatsServer();
926 http_pipelining_test_server_ = dist->GetHttpPipeliningTestServer();
927 #endif
929 PrefService* pref = g_browser_process->local_state();
930 DCHECK(pref);
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
952 // monitoring.
953 pref->SetBoolean(prefs::kStabilityExitedCleanly, true);
955 // TODO(rtenneti): On windows, consider saving/getting execution_phase from
956 // the registry.
957 int execution_phase = pref->GetInteger(prefs::kStabilityExecutionPhase);
958 UMA_HISTOGRAM_SPARSE_SLOWLY("Chrome.Browser.CrashedExecutionPhase",
959 execution_phase);
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.
969 ++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);
978 #if defined(OS_WIN)
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)) {
1003 ++common_commands;
1004 UMA_HISTOGRAM_COUNTS_100("Chrome.CommandLineDatDirCount", 1);
1007 if (command_line->HasSwitch(switches::kApp)) {
1008 ++common_commands;
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();
1022 // static
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()));
1049 #else
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_);
1058 plugins_ = plugins;
1060 // Schedules a task on a blocking pool thread to gather Google Update
1061 // statistics (requires Registry reads).
1062 BrowserThread::PostBlockingPoolTask(
1063 FROM_HERE,
1064 base::Bind(&MetricsService::InitTaskGetGoogleUpdateData,
1065 self_ptr_factory_.GetWeakPtr(),
1066 base::MessageLoop::current()->message_loop_proxy()));
1069 // static
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(
1084 system_install,
1085 &google_update_metrics.google_update_data);
1086 GoogleUpdateSettings::GetUpdateDetail(
1087 system_install,
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())
1110 return;
1112 log_manager_.current_log()->RecordUserAction(action.c_str());
1113 HandleIdleSinceLastTransmission(false);
1116 void MetricsService::ReceivedProfilerData(
1117 const tracked_objects::ProcessDataSnapshot& process_data,
1118 int process_type) {
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.
1170 if (value == 8192)
1171 value = 0;
1172 // If the value is outside the [0, kMaxLowEntropySize) range, re-generate
1173 // it below.
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_;
1189 // static
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();
1208 if (!pref) {
1209 NOTREACHED();
1210 return;
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
1235 // thread.
1236 BrowserThread::PostDelayedTask(
1237 BrowserThread::FILE,
1238 FROM_HERE,
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())
1248 return;
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_,
1272 synthetic_trials);
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;
1291 else
1292 store_type = MetricsLogManager::NORMAL_STORE;
1293 log_manager_.StoreStagedLogAsUnsent(store_type);
1295 DCHECK(!log_manager_.has_staged_log());
1296 CloseCurrentLog();
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_)
1311 return;
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)) {
1334 scheduler_->Stop();
1335 scheduler_->UploadCancelled();
1336 return;
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
1341 // callbacks.
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 */);
1348 return;
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();
1355 SendStagedLog();
1356 } else {
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
1388 // step.
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;
1404 #else // OS_ANDROID
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,
1421 timeout);
1424 void MetricsService::OnHistogramSynchronizationDone() {
1425 DCHECK(IsSingleThreaded());
1426 // This function should only be called as the callback from an ansynchronous
1427 // step.
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)
1433 return;
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())
1445 return;
1447 // Abort if metrics were turned off during the final info gathering.
1448 if (!recording_active()) {
1449 scheduler_->Stop();
1450 scheduler_->UploadCancelled();
1451 return;
1454 StageNewLog();
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()) {
1463 scheduler_->Stop();
1464 scheduler_->UploadCancelled();
1465 return;
1468 SendStagedLog();
1471 void MetricsService::StageNewLog() {
1472 if (log_manager_.has_staged_log())
1473 return;
1475 switch (state_) {
1476 case INITIALIZED:
1477 case INIT_TASK_SCHEDULED: // We should be further along by now.
1478 NOTREACHED();
1479 return;
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;
1487 } else {
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;
1501 break;
1503 case SENDING_OLD_LOGS:
1504 NOTREACHED(); // Shouldn't be staging a new log during old log sending.
1505 return;
1507 case SENDING_CURRENT_LOGS:
1508 CloseCurrentLog();
1509 OpenNewLog();
1510 log_manager_.StageNextLogForUpload();
1511 break;
1513 default:
1514 NOTREACHED();
1515 return;
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())
1529 return;
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_,
1554 synthetic_trials);
1555 PrefService* pref = g_browser_process->local_state();
1556 initial_metrics_log_->RecordStabilityMetrics(GetIncrementalUptime(pref),
1557 log_type);
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();
1583 return;
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,
1625 1, 2000, 50);
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));
1663 discard_log = true;
1664 } else if (response_code == 400) {
1665 // Bad syntax. Retransmission won't work.
1666 discard_log = true;
1669 if (upload_succeeded || discard_log)
1670 log_manager_.DiscardStagedLog();
1672 waiting_for_asynchronous_reporting_step_ = false;
1674 if (!log_manager_.has_staged_log()) {
1675 switch (state_) {
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);
1680 SendStagedLog();
1681 state_ = SENDING_INITIAL_METRICS_LOG;
1682 break;
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;
1691 break;
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;
1698 break;
1700 case SENDING_CURRENT_LOGS:
1701 break;
1703 default:
1704 NOTREACHED();
1705 break;
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);
1729 #if defined(OS_WIN)
1730 chrome::CollectTimeTicksStats();
1731 #endif
1735 void MetricsService::IncrementPrefValue(const char* path) {
1736 PrefService* pref = g_browser_process->local_state();
1737 DCHECK(pref);
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();
1744 DCHECK(pref);
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,
1760 int exit_code) {
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));
1771 } else {
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;
1807 return;
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);
1850 else
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;
1860 bool success =
1861 content::PluginService::GetInstance()->GetPluginInfoByPath(plugin_path,
1862 &plugin);
1863 DCHECK(success);
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;
1870 } else {
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();
1889 DCHECK(plugins);
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)) {
1894 NOTREACHED();
1895 continue;
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()) {
1903 NOTREACHED();
1904 continue;
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()) {
1911 continue;
1914 ChildProcessStats stats = child_process_stats_buffer_[name16];
1915 if (stats.process_launches) {
1916 int launches = 0;
1917 plugin_dict->GetInteger(prefs::kStabilityPluginLaunches, &launches);
1918 launches += stats.process_launches;
1919 plugin_dict->SetInteger(prefs::kStabilityPluginLaunches, launches);
1921 if (stats.process_crashes) {
1922 int crashes = 0;
1923 plugin_dict->GetInteger(prefs::kStabilityPluginCrashes, &crashes);
1924 crashes += stats.process_crashes;
1925 plugin_dict->SetInteger(prefs::kStabilityPluginCrashes, crashes);
1927 if (stats.instances) {
1928 int instances = 0;
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,
1936 &loading_errors);
1937 loading_errors += stats.loading_errors;
1938 plugin_dict->SetInteger(prefs::kStabilityPluginLoadingErrors,
1939 loading_errors);
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))
1954 continue;
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,
1967 stats.instances);
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();
1986 DCHECK(pref);
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);
1998 // static
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();
2010 #endif
2012 // static
2013 bool MetricsServiceHelper::IsMetricsReportingEnabled() {
2014 bool result = false;
2015 const PrefService* local_state = g_browser_process->local_state();
2016 if (local_state) {
2017 const PrefService::Preference* uma_pref =
2018 local_state->FindPreference(prefs::kMetricsReportingEnabled);
2019 if (uma_pref) {
2020 bool success = uma_pref->GetValue()->GetAsBoolean(&result);
2021 DCHECK(success);
2024 return result;