blob: eb540de46caa7ca0272a23b4e9f3eb2b220e382f [file] [log] [blame]
[email protected]f90bf0d92011-01-13 02:12:441// Copyright (c) 2011 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit09911bf2008-07-26 23:55:294
initial.commit09911bf2008-07-26 23:55:295//------------------------------------------------------------------------------
6// Description of the life cycle of a instance of MetricsService.
7//
8// OVERVIEW
9//
10// A MetricsService instance is typically created at application startup. It
11// is 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 XML text, and compressing the results for
17// transmission. Transmission includes submitting a compressed log as data in a
[email protected]281d2882009-01-20 20:32:4218// URL-post, and retransmitting (or retaining at process termination) if the
initial.commit09911bf2008-07-26 23:55:2919// attempted transmission failed. Retention across process terminations is done
[email protected]46f89e142010-07-19 08:00:4220// using the the PrefServices facilities. The retained logs (the ones that never
21// got transmitted) are compressed and base64-encoded before being persisted.
initial.commit09911bf2008-07-26 23:55:2922//
[email protected]281d2882009-01-20 20:32:4223// Logs fall into one of two categories: "initial logs," and "ongoing logs."
24// There is at most one initial log sent for each complete run of the chromium
initial.commit09911bf2008-07-26 23:55:2925// product (from startup, to browser shutdown). An initial log is generally
26// transmitted some short time (1 minute?) after startup, and includes stats
27// such as recent crash info, the number and types of plugins, etc. The
[email protected]281d2882009-01-20 20:32:4228// external server's response to the initial log conceptually tells this MS if
29// it should continue transmitting logs (during this session). The server
30// response can actually be much more detailed, and always includes (at a
31// minimum) how often additional ongoing logs should be sent.
initial.commit09911bf2008-07-26 23:55:2932//
33// After the above initial log, a series of ongoing logs will be transmitted.
34// The first ongoing log actually begins to accumulate information stating when
35// the MS was first constructed. Note that even though the initial log is
36// commonly sent a full minute after startup, the initial log does not include
37// much in the way of user stats. The most common interlog period (delay)
[email protected]0b33f80b2008-12-17 21:34:3638// is 20 minutes. That time period starts when the first user action causes a
initial.commit09911bf2008-07-26 23:55:2939// logging event. This means that if there is no user action, there may be long
[email protected]281d2882009-01-20 20:32:4240// periods without any (ongoing) log transmissions. Ongoing logs typically
initial.commit09911bf2008-07-26 23:55:2941// contain very detailed records of user activities (ex: opened tab, closed
42// tab, fetched URL, maximized window, etc.) In addition, just before an
43// ongoing log is closed out, a call is made to gather memory statistics. Those
44// memory statistics are deposited into a histogram, and the log finalization
45// code is then called. In the finalization, a call to a Histogram server
46// acquires a list of all local histograms that have been flagged for upload
[email protected]281d2882009-01-20 20:32:4247// to the UMA server. The finalization also acquires a the most recent number
48// of page loads, along with any counts of renderer or plugin crashes.
initial.commit09911bf2008-07-26 23:55:2949//
50// When the browser shuts down, there will typically be a fragment of an ongoing
51// log that has not yet been transmitted. At shutdown time, that fragment
52// is closed (including snapshotting histograms), and converted to text. Note
53// that memory stats are not gathered during shutdown, as gathering *might* be
54// too time consuming. The textual representation of the fragment of the
55// ongoing log is then stored persistently as a string in the PrefServices, for
56// potential transmission during a future run of the product.
57//
58// There are two slightly abnormal shutdown conditions. There is a
59// "disconnected scenario," and a "really fast startup and shutdown" scenario.
60// In the "never connected" situation, the user has (during the running of the
61// process) never established an internet connection. As a result, attempts to
62// transmit the initial log have failed, and a lot(?) of data has accumulated in
63// the ongoing log (which didn't yet get closed, because there was never even a
64// contemplation of sending it). There is also a kindred "lost connection"
65// situation, where a loss of connection prevented an ongoing log from being
66// transmitted, and a (still open) log was stuck accumulating a lot(?) of data,
67// while the earlier log retried its transmission. In both of these
68// disconnected situations, two logs need to be, and are, persistently stored
69// for future transmission.
70//
71// The other unusual shutdown condition, termed "really fast startup and
72// shutdown," involves the deliberate user termination of the process before
73// the initial log is even formed or transmitted. In that situation, no logging
74// is done, but the historical crash statistics remain (unlogged) for inclusion
75// in a future run's initial log. (i.e., we don't lose crash stats).
76//
77// With the above overview, we can now describe the state machine's various
78// stats, based on the State enum specified in the state_ member. Those states
79// are:
80//
81// INITIALIZED, // Constructor was called.
[email protected]85ed9d42010-06-08 22:37:4482// INIT_TASK_SCHEDULED, // Waiting for deferred init tasks to complete.
83// INIT_TASK_DONE, // Waiting for timer to send initial log.
initial.commit09911bf2008-07-26 23:55:2984// INITIAL_LOG_READY, // Initial log generated, and waiting for reply.
85// SEND_OLD_INITIAL_LOGS, // Sending unsent logs from previous session.
86// SENDING_OLD_LOGS, // Sending unsent logs from previous session.
87// SENDING_CURRENT_LOGS, // Sending standard current logs as they accrue.
88//
89// In more detail, we have:
90//
91// INITIALIZED, // Constructor was called.
92// The MS has been constructed, but has taken no actions to compose the
93// initial log.
94//
[email protected]85ed9d42010-06-08 22:37:4495// INIT_TASK_SCHEDULED, // Waiting for deferred init tasks to complete.
initial.commit09911bf2008-07-26 23:55:2996// Typically about 30 seconds after startup, a task is sent to a second thread
[email protected]85ed9d42010-06-08 22:37:4497// (the file thread) to perform deferred (lower priority and slower)
98// initialization steps such as getting the list of plugins. That task will
99// (when complete) make an async callback (via a Task) to indicate the
100// completion.
initial.commit09911bf2008-07-26 23:55:29101//
[email protected]85ed9d42010-06-08 22:37:44102// INIT_TASK_DONE, // Waiting for timer to send initial log.
initial.commit09911bf2008-07-26 23:55:29103// The callback has arrived, and it is now possible for an initial log to be
104// created. This callback typically arrives back less than one second after
[email protected]85ed9d42010-06-08 22:37:44105// the deferred init task is dispatched.
initial.commit09911bf2008-07-26 23:55:29106//
107// INITIAL_LOG_READY, // Initial log generated, and waiting for reply.
108// This state is entered only after an initial log has been composed, and
109// prepared for transmission. It is also the case that any previously unsent
110// logs have been loaded into instance variables for possible transmission.
111//
112// SEND_OLD_INITIAL_LOGS, // Sending unsent logs from previous session.
113// This state indicates that the initial log for this session has been
114// successfully sent and it is now time to send any "initial logs" that were
115// saved from previous sessions. Most commonly, there are none, but all old
116// logs that were "initial logs" must be sent before this state is exited.
117//
118// SENDING_OLD_LOGS, // Sending unsent logs from previous session.
119// This state indicates that there are no more unsent initial logs, and now any
120// ongoing logs from previous sessions should be transmitted. All such logs
121// will be transmitted before exiting this state, and proceeding with ongoing
122// logs from the current session (see next state).
123//
124// SENDING_CURRENT_LOGS, // Sending standard current logs as they accrue.
[email protected]0b33f80b2008-12-17 21:34:36125// Current logs are being accumulated. Typically every 20 minutes a log is
initial.commit09911bf2008-07-26 23:55:29126// closed and finalized for transmission, at the same time as a new log is
127// started.
128//
129// The progression through the above states is simple, and sequential, in the
130// most common use cases. States proceed from INITIAL to SENDING_CURRENT_LOGS,
131// and remain in the latter until shutdown.
132//
133// The one unusual case is when the user asks that we stop logging. When that
134// happens, any pending (transmission in progress) log is pushed into the list
135// of old unsent logs (the appropriate list, depending on whether it is an
136// initial log, or an ongoing log). An addition, any log that is currently
137// accumulating is also finalized, and pushed into the unsent log list. With
[email protected]281d2882009-01-20 20:32:42138// those pushes performed, we regress back to the SEND_OLD_INITIAL_LOGS state in
initial.commit09911bf2008-07-26 23:55:29139// case the user enables log recording again during this session. This way
140// anything we have "pushed back" will be sent automatically if/when we progress
141// back to SENDING_CURRENT_LOG state.
142//
143// Also note that whenever the member variables containing unsent logs are
144// modified (i.e., when we send an old log), we mirror the list of logs into
145// the PrefServices. This ensures that IF we crash, we won't start up and
146// retransmit our old logs again.
147//
148// Due to race conditions, it is always possible that a log file could be sent
149// twice. For example, if a log file is sent, but not yet acknowledged by
150// the external server, and the user shuts down, then a copy of the log may be
151// saved for re-transmission. These duplicates could be filtered out server
[email protected]281d2882009-01-20 20:32:42152// side, but are not expected to be a significant problem.
initial.commit09911bf2008-07-26 23:55:29153//
154//
155//------------------------------------------------------------------------------
156
[email protected]40bcc302009-03-02 20:50:39157#include "chrome/browser/metrics/metrics_service.h"
158
[email protected]46f89e142010-07-19 08:00:42159#include "base/base64.h"
[email protected]7f7f1962011-04-20 15:58:16160#include "base/bind.h"
161#include "base/callback.h"
[email protected]5d91c9e2010-07-28 17:25:28162#include "base/command_line.h"
[email protected]46f89e142010-07-19 08:00:42163#include "base/md5.h"
[email protected]835d7c82010-10-14 04:38:38164#include "base/metrics/histogram.h"
[email protected]528c56d2010-07-30 19:28:44165#include "base/string_number_conversions.h"
[email protected]e257d5b2011-05-25 14:10:16166#include "base/string_util.h" // For WriteInto().
[email protected]ce072a72010-12-31 20:02:16167#include "base/threading/platform_thread.h"
[email protected]b3841c502011-03-09 01:21:31168#include "base/threading/thread.h"
[email protected]440b37b22010-08-30 05:31:40169#include "base/utf_string_conversions.h"
[email protected]679082052010-07-21 21:30:13170#include "base/values.h"
[email protected]d8e41ed2008-09-11 15:22:32171#include "chrome/browser/bookmarks/bookmark_model.h"
initial.commit09911bf2008-07-26 23:55:29172#include "chrome/browser/browser_process.h"
[email protected]84c988a2011-04-19 17:56:33173#include "chrome/browser/memory_details.h"
[email protected]7c927b62010-02-24 09:54:13174#include "chrome/browser/metrics/histogram_synchronizer.h"
[email protected]679082052010-07-21 21:30:13175#include "chrome/browser/metrics/metrics_log.h"
[email protected]7f7f1962011-04-20 15:58:16176#include "chrome/browser/metrics/metrics_reporting_scheduler.h"
[email protected]d67d1052011-06-09 05:11:41177#include "chrome/browser/net/network_stats.h"
[email protected]37858e52010-08-26 00:22:02178#include "chrome/browser/prefs/pref_service.h"
[email protected]f8628c22011-04-05 12:10:18179#include "chrome/browser/prefs/scoped_user_pref_update.h"
[email protected]8ecad5e2010-12-02 21:18:33180#include "chrome/browser/profiles/profile.h"
[email protected]8e5c89a2011-06-07 18:13:33181#include "chrome/browser/search_engines/template_url_service.h"
[email protected]71b73f02011-04-06 15:57:29182#include "chrome/browser/ui/browser_list.h"
[email protected]157d5472009-11-05 22:31:03183#include "chrome/common/child_process_logging.h"
[email protected]432115822011-07-10 15:52:27184#include "chrome/common/chrome_notification_types.h"
[email protected]92745242009-06-12 16:52:21185#include "chrome/common/chrome_switches.h"
[email protected]3eb0d8f72010-12-15 23:38:25186#include "chrome/common/guid.h"
initial.commit09911bf2008-07-26 23:55:29187#include "chrome/common/pref_names.h"
[email protected]e09ba552009-02-05 03:26:29188#include "chrome/common/render_messages.h"
[email protected]35e251d2011-05-24 21:01:04189#include "content/browser/load_notification_details.h"
[email protected]5de634712011-03-02 00:20:19190#include "content/browser/renderer_host/render_process_host.h"
[email protected]6faf7b12011-03-09 19:24:14191#include "content/common/child_process_info.h"
[email protected]b3841c502011-03-09 01:21:31192#include "content/common/notification_service.h"
[email protected]191eb3f72010-12-21 06:27:50193#include "webkit/plugins/npapi/plugin_list.h"
194#include "webkit/plugins/npapi/webplugininfo.h"
initial.commit09911bf2008-07-26 23:55:29195
[email protected]e06131d2010-02-10 18:40:33196// TODO(port): port browser_distribution.h.
197#if !defined(OS_POSIX)
[email protected]79bf0b72009-04-27 21:30:55198#include "chrome/installer/util/browser_distribution.h"
[email protected]dc6f4962009-02-13 01:25:50199#endif
200
[email protected]5ccaa412009-11-13 22:00:16201#if defined(OS_CHROMEOS)
[email protected]db342d52010-08-09 21:19:37202#include "chrome/browser/chromeos/cros/cros_library.h"
[email protected]5ccaa412009-11-13 22:00:16203#include "chrome/browser/chromeos/external_metrics.h"
[email protected]d43970a72011-07-10 06:24:52204#include "chrome/browser/chromeos/system/statistics_provider.h"
[email protected]5ccaa412009-11-13 22:00:16205#endif
206
[email protected]46f89e142010-07-19 08:00:42207namespace {
208MetricsService::LogRecallStatus MakeRecallStatusHistogram(
209 MetricsService::LogRecallStatus status) {
210 UMA_HISTOGRAM_ENUMERATION("PrefService.PersistentLogRecall", status,
211 MetricsService::END_RECALL_STATUS);
212 return status;
213}
214
215// TODO(ziadh): Remove this when done with experiment.
216void MakeStoreStatusHistogram(MetricsService::LogStoreStatus status) {
[email protected]4e95d202010-07-24 01:47:56217 UMA_HISTOGRAM_ENUMERATION("PrefService.PersistentLogStore2", status,
[email protected]46f89e142010-07-19 08:00:42218 MetricsService::END_STORE_STATUS);
219}
220} // namespace
221
[email protected]e1acf6f2008-10-27 20:43:33222using base::Time;
[email protected]e1acf6f2008-10-27 20:43:33223
initial.commit09911bf2008-07-26 23:55:29224// Check to see that we're being called on only one thread.
225static bool IsSingleThreaded();
226
initial.commit09911bf2008-07-26 23:55:29227static const char kMetricsType[] = "application/vnd.mozilla.metrics.bz2";
228
[email protected]7f7f1962011-04-20 15:58:16229// The delay, in seconds, after starting recording before doing expensive
230// initialization work.
231static const int kInitializationDelaySeconds = 30;
[email protected]252873ef2008-08-04 21:59:45232
[email protected]c9a3ef82009-05-28 22:02:46233// This specifies the amount of time to wait for all renderers to send their
234// data.
235static const int kMaxHistogramGatheringWaitDuration = 60000; // 60 seconds.
236
[email protected]54702c92011-04-15 15:06:43237// The maximum number of events in a log uploaded to the UMA server.
238static const int kEventLimit = 2400;
[email protected]68475e602008-08-22 03:21:15239
240// If an upload fails, and the transmission was over this byte count, then we
241// will discard the log, and not try to retransmit it. We also don't persist
242// the log to the prefs for transmission during the next chrome session if this
243// limit is exceeded.
244static const int kUploadLogAvoidRetransmitSize = 50000;
initial.commit09911bf2008-07-26 23:55:29245
initial.commit09911bf2008-07-26 23:55:29246// Interval, in seconds, between state saves.
247static const int kSaveStateInterval = 5 * 60; // five minutes
248
249// The number of "initial" logs we're willing to save, and hope to send during
250// a future Chrome session. Initial logs contain crash stats, and are pretty
251// small.
252static const size_t kMaxInitialLogsPersisted = 20;
253
254// The number of ongoing logs we're willing to save persistently, and hope to
[email protected]281d2882009-01-20 20:32:42255// send during a this or future sessions. Note that each log may be pretty
initial.commit09911bf2008-07-26 23:55:29256// large, as presumably the related "initial" log wasn't sent (probably nothing
257// was, as the user was probably off-line). As a result, the log probably kept
258// accumulating while the "initial" log was stalled (pending_), and couldn't be
259// sent. As a result, we don't want to save too many of these mega-logs.
260// A "standard shutdown" will create a small log, including just the data that
261// was not yet been transmitted, and that is normal (to have exactly one
262// ongoing_log_ at startup).
[email protected]281d2882009-01-20 20:32:42263static const size_t kMaxOngoingLogsPersisted = 8;
initial.commit09911bf2008-07-26 23:55:29264
[email protected]46f89e142010-07-19 08:00:42265// We append (2) more elements to persisted lists: the size of the list and a
266// checksum of the elements.
267static const size_t kChecksumEntryCount = 2;
268
[email protected]679082052010-07-21 21:30:13269// This is used to quickly log stats from child process related notifications in
270// MetricsService::child_stats_buffer_. The buffer's contents are transferred
271// out when Local State is periodically saved. The information is then
272// reported to the UMA server on next launch.
273struct MetricsService::ChildProcessStats {
274 public:
275 explicit ChildProcessStats(ChildProcessInfo::ProcessType type)
276 : process_launches(0),
277 process_crashes(0),
278 instances(0),
279 process_type(type) {}
280
281 // This constructor is only used by the map to return some default value for
282 // an index for which no value has been assigned.
283 ChildProcessStats()
284 : process_launches(0),
285 process_crashes(0),
286 instances(0),
287 process_type(ChildProcessInfo::UNKNOWN_PROCESS) {}
288
289 // The number of times that the given child process has been launched
290 int process_launches;
291
292 // The number of times that the given child process has crashed
293 int process_crashes;
294
295 // The number of instances of this child process that have been created.
296 // An instance is a DOM object rendered by this child process during a page
297 // load.
298 int instances;
299
300 ChildProcessInfo::ProcessType process_type;
301};
initial.commit09911bf2008-07-26 23:55:29302
[email protected]84c988a2011-04-19 17:56:33303// Handles asynchronous fetching of memory details.
304// Will run the provided task after finished.
305class MetricsMemoryDetails : public MemoryDetails {
306 public:
307 explicit MetricsMemoryDetails(Task* completion) : completion_(completion) {}
308
309 virtual void OnDetailsAvailable() {
310 MessageLoop::current()->PostTask(FROM_HERE, completion_);
311 }
312
313 private:
314 ~MetricsMemoryDetails() {}
315
316 Task* completion_;
317 DISALLOW_COPY_AND_ASSIGN(MetricsMemoryDetails);
318};
319
[email protected]85ed9d42010-06-08 22:37:44320class MetricsService::InitTaskComplete : public Task {
[email protected]35fa6a22009-08-15 00:04:01321 public:
[email protected]191eb3f72010-12-21 06:27:50322 explicit InitTaskComplete(
323 const std::string& hardware_class,
324 const std::vector<webkit::npapi::WebPluginInfo>& plugins)
[email protected]85ed9d42010-06-08 22:37:44325 : hardware_class_(hardware_class), plugins_(plugins) {}
326
[email protected]7f2e792e2009-11-30 23:18:29327 virtual void Run() {
[email protected]85ed9d42010-06-08 22:37:44328 g_browser_process->metrics_service()->OnInitTaskComplete(
329 hardware_class_, plugins_);
initial.commit09911bf2008-07-26 23:55:29330 }
[email protected]35fa6a22009-08-15 00:04:01331
[email protected]7f2e792e2009-11-30 23:18:29332 private:
[email protected]85ed9d42010-06-08 22:37:44333 std::string hardware_class_;
[email protected]191eb3f72010-12-21 06:27:50334 std::vector<webkit::npapi::WebPluginInfo> plugins_;
initial.commit09911bf2008-07-26 23:55:29335};
336
[email protected]85ed9d42010-06-08 22:37:44337class MetricsService::InitTask : public Task {
[email protected]7f2e792e2009-11-30 23:18:29338 public:
[email protected]85ed9d42010-06-08 22:37:44339 explicit InitTask(MessageLoop* callback_loop)
[email protected]7f2e792e2009-11-30 23:18:29340 : callback_loop_(callback_loop) {}
341
342 virtual void Run() {
[email protected]191eb3f72010-12-21 06:27:50343 std::vector<webkit::npapi::WebPluginInfo> plugins;
[email protected]68598072011-07-29 08:21:28344 webkit::npapi::PluginList::Singleton()->GetPlugins(&plugins);
[email protected]85ed9d42010-06-08 22:37:44345 std::string hardware_class; // Empty string by default.
346#if defined(OS_CHROMEOS)
[email protected]d43970a72011-07-10 06:24:52347 chromeos::system::StatisticsProvider::GetInstance()->GetMachineStatistic(
[email protected]9b345162011-04-15 05:21:30348 "hardware_class", &hardware_class);
[email protected]85ed9d42010-06-08 22:37:44349#endif // OS_CHROMEOS
350 callback_loop_->PostTask(FROM_HERE, new InitTaskComplete(
351 hardware_class, plugins));
[email protected]7f2e792e2009-11-30 23:18:29352 }
353
354 private:
355 MessageLoop* callback_loop_;
356};
[email protected]90d41372009-11-30 21:52:32357
initial.commit09911bf2008-07-26 23:55:29358// static
359void MetricsService::RegisterPrefs(PrefService* local_state) {
360 DCHECK(IsSingleThreaded());
[email protected]20ce516d2010-06-18 02:20:04361 local_state->RegisterStringPref(prefs::kMetricsClientID, "");
[email protected]0bb1a622009-03-04 03:22:32362 local_state->RegisterInt64Pref(prefs::kMetricsClientIDTimestamp, 0);
363 local_state->RegisterInt64Pref(prefs::kStabilityLaunchTimeSec, 0);
364 local_state->RegisterInt64Pref(prefs::kStabilityLastTimestampSec, 0);
[email protected]20ce516d2010-06-18 02:20:04365 local_state->RegisterStringPref(prefs::kStabilityStatsVersion, "");
[email protected]225c50842010-01-19 21:19:13366 local_state->RegisterInt64Pref(prefs::kStabilityStatsBuildTime, 0);
initial.commit09911bf2008-07-26 23:55:29367 local_state->RegisterBooleanPref(prefs::kStabilityExitedCleanly, true);
368 local_state->RegisterBooleanPref(prefs::kStabilitySessionEndCompleted, true);
369 local_state->RegisterIntegerPref(prefs::kMetricsSessionID, -1);
370 local_state->RegisterIntegerPref(prefs::kStabilityLaunchCount, 0);
371 local_state->RegisterIntegerPref(prefs::kStabilityCrashCount, 0);
372 local_state->RegisterIntegerPref(prefs::kStabilityIncompleteSessionEndCount,
373 0);
374 local_state->RegisterIntegerPref(prefs::kStabilityPageLoadCount, 0);
initial.commit09911bf2008-07-26 23:55:29375 local_state->RegisterIntegerPref(prefs::kStabilityRendererCrashCount, 0);
[email protected]1f085622009-12-04 05:33:45376 local_state->RegisterIntegerPref(prefs::kStabilityExtensionRendererCrashCount,
377 0);
initial.commit09911bf2008-07-26 23:55:29378 local_state->RegisterIntegerPref(prefs::kStabilityRendererHangCount, 0);
[email protected]1f085622009-12-04 05:33:45379 local_state->RegisterIntegerPref(prefs::kStabilityChildProcessCrashCount, 0);
[email protected]e73c01972008-08-13 00:18:24380 local_state->RegisterIntegerPref(prefs::kStabilityBreakpadRegistrationFail,
381 0);
382 local_state->RegisterIntegerPref(prefs::kStabilityBreakpadRegistrationSuccess,
383 0);
384 local_state->RegisterIntegerPref(prefs::kStabilityDebuggerPresent, 0);
385 local_state->RegisterIntegerPref(prefs::kStabilityDebuggerNotPresent, 0);
[email protected]c1834a92011-01-21 18:21:03386#if defined(OS_CHROMEOS)
387 local_state->RegisterIntegerPref(prefs::kStabilityOtherUserCrashCount, 0);
388 local_state->RegisterIntegerPref(prefs::kStabilityKernelCrashCount, 0);
389 local_state->RegisterIntegerPref(prefs::kStabilitySystemUncleanShutdownCount,
390 0);
391#endif // OS_CHROMEOS
[email protected]e73c01972008-08-13 00:18:24392
initial.commit09911bf2008-07-26 23:55:29393 local_state->RegisterDictionaryPref(prefs::kProfileMetrics);
394 local_state->RegisterIntegerPref(prefs::kNumBookmarksOnBookmarkBar, 0);
395 local_state->RegisterIntegerPref(prefs::kNumFoldersOnBookmarkBar, 0);
396 local_state->RegisterIntegerPref(prefs::kNumBookmarksInOtherBookmarkFolder,
397 0);
398 local_state->RegisterIntegerPref(prefs::kNumFoldersInOtherBookmarkFolder, 0);
399 local_state->RegisterIntegerPref(prefs::kNumKeywords, 0);
400 local_state->RegisterListPref(prefs::kMetricsInitialLogs);
401 local_state->RegisterListPref(prefs::kMetricsOngoingLogs);
[email protected]0bb1a622009-03-04 03:22:32402
403 local_state->RegisterInt64Pref(prefs::kUninstallMetricsPageLoadCount, 0);
404 local_state->RegisterInt64Pref(prefs::kUninstallLaunchCount, 0);
[email protected]6b5f21d2009-04-13 17:01:35405 local_state->RegisterInt64Pref(prefs::kUninstallMetricsInstallDate, 0);
[email protected]0bb1a622009-03-04 03:22:32406 local_state->RegisterInt64Pref(prefs::kUninstallMetricsUptimeSec, 0);
407 local_state->RegisterInt64Pref(prefs::kUninstallLastLaunchTimeSec, 0);
408 local_state->RegisterInt64Pref(prefs::kUninstallLastObservedRunTimeSec, 0);
initial.commit09911bf2008-07-26 23:55:29409}
410
[email protected]541f77922009-02-23 21:14:38411// static
412void MetricsService::DiscardOldStabilityStats(PrefService* local_state) {
413 local_state->SetBoolean(prefs::kStabilityExitedCleanly, true);
[email protected]c9abf242009-07-18 06:00:38414 local_state->SetBoolean(prefs::kStabilitySessionEndCompleted, true);
[email protected]541f77922009-02-23 21:14:38415
416 local_state->SetInteger(prefs::kStabilityIncompleteSessionEndCount, 0);
417 local_state->SetInteger(prefs::kStabilityBreakpadRegistrationSuccess, 0);
418 local_state->SetInteger(prefs::kStabilityBreakpadRegistrationFail, 0);
419 local_state->SetInteger(prefs::kStabilityDebuggerPresent, 0);
420 local_state->SetInteger(prefs::kStabilityDebuggerNotPresent, 0);
421
422 local_state->SetInteger(prefs::kStabilityLaunchCount, 0);
423 local_state->SetInteger(prefs::kStabilityCrashCount, 0);
424
425 local_state->SetInteger(prefs::kStabilityPageLoadCount, 0);
426 local_state->SetInteger(prefs::kStabilityRendererCrashCount, 0);
427 local_state->SetInteger(prefs::kStabilityRendererHangCount, 0);
428
[email protected]9165f742010-03-10 22:55:01429 local_state->SetInt64(prefs::kStabilityLaunchTimeSec, 0);
430 local_state->SetInt64(prefs::kStabilityLastTimestampSec, 0);
[email protected]541f77922009-02-23 21:14:38431
432 local_state->ClearPref(prefs::kStabilityPluginStats);
[email protected]ae155cb92009-06-19 06:10:37433
[email protected]f8628c22011-04-05 12:10:18434 local_state->ClearPref(prefs::kMetricsInitialLogs);
435 local_state->ClearPref(prefs::kMetricsOngoingLogs);
[email protected]541f77922009-02-23 21:14:38436}
437
initial.commit09911bf2008-07-26 23:55:29438MetricsService::MetricsService()
[email protected]d01b8732008-10-16 02:18:07439 : recording_active_(false),
440 reporting_active_(false),
[email protected]d01b8732008-10-16 02:18:07441 state_(INITIALIZED),
initial.commit09911bf2008-07-26 23:55:29442 current_fetch_(NULL),
[email protected]d67d1052011-06-09 05:11:41443 io_thread_(NULL),
[email protected]d01b8732008-10-16 02:18:07444 idle_since_last_transmission_(false),
initial.commit09911bf2008-07-26 23:55:29445 next_window_id_(0),
[email protected]40bcc302009-03-02 20:50:39446 ALLOW_THIS_IN_INITIALIZER_LIST(log_sender_factory_(this)),
447 ALLOW_THIS_IN_INITIALIZER_LIST(state_saver_factory_(this)),
[email protected]7f7f1962011-04-20 15:58:16448 waiting_for_asynchronus_reporting_step_(false) {
initial.commit09911bf2008-07-26 23:55:29449 DCHECK(IsSingleThreaded());
450 InitializeMetricsState();
[email protected]7f7f1962011-04-20 15:58:16451
452 base::Closure callback = base::Bind(&MetricsService::StartScheduledUpload,
453 base::Unretained(this));
454 scheduler_.reset(new MetricsReportingScheduler(callback));
initial.commit09911bf2008-07-26 23:55:29455}
456
457MetricsService::~MetricsService() {
458 SetRecording(false);
459}
460
[email protected]d01b8732008-10-16 02:18:07461void MetricsService::Start() {
[email protected]b1c8dc02011-04-13 18:32:04462 HandleIdleSinceLastTransmission(false);
[email protected]d01b8732008-10-16 02:18:07463 SetRecording(true);
464 SetReporting(true);
465}
466
467void MetricsService::StartRecordingOnly() {
468 SetRecording(true);
469 SetReporting(false);
470}
471
472void MetricsService::Stop() {
[email protected]b1c8dc02011-04-13 18:32:04473 HandleIdleSinceLastTransmission(false);
[email protected]d01b8732008-10-16 02:18:07474 SetReporting(false);
475 SetRecording(false);
476}
477
[email protected]edafd4c2011-05-10 17:18:53478std::string MetricsService::GetClientId() {
479 return client_id_;
480}
481
initial.commit09911bf2008-07-26 23:55:29482void MetricsService::SetRecording(bool enabled) {
483 DCHECK(IsSingleThreaded());
484
[email protected]d01b8732008-10-16 02:18:07485 if (enabled == recording_active_)
initial.commit09911bf2008-07-26 23:55:29486 return;
487
488 if (enabled) {
[email protected]b0c819f2009-03-08 04:52:15489 if (client_id_.empty()) {
490 PrefService* pref = g_browser_process->local_state();
491 DCHECK(pref);
[email protected]ddd231e2010-06-29 20:35:19492 client_id_ = pref->GetString(prefs::kMetricsClientID);
[email protected]b0c819f2009-03-08 04:52:15493 if (client_id_.empty()) {
494 client_id_ = GenerateClientID();
[email protected]ddd231e2010-06-29 20:35:19495 pref->SetString(prefs::kMetricsClientID, client_id_);
[email protected]b0c819f2009-03-08 04:52:15496
497 // Might as well make a note of how long this ID has existed
498 pref->SetString(prefs::kMetricsClientIDTimestamp,
[email protected]528c56d2010-07-30 19:28:44499 base::Int64ToString(Time::Now().ToTimeT()));
[email protected]b0c819f2009-03-08 04:52:15500 }
501 }
[email protected]157d5472009-11-05 22:31:03502 child_process_logging::SetClientId(client_id_);
initial.commit09911bf2008-07-26 23:55:29503 StartRecording();
[email protected]005ef3e2009-05-22 20:55:46504
[email protected]3ffd3ae2011-03-17 22:17:52505 SetUpNotifications(&registrar_, this);
initial.commit09911bf2008-07-26 23:55:29506 } else {
[email protected]005ef3e2009-05-22 20:55:46507 registrar_.RemoveAll();
initial.commit09911bf2008-07-26 23:55:29508 PushPendingLogsToUnsentLists();
509 DCHECK(!pending_log());
510 if (state_ > INITIAL_LOG_READY && unsent_logs())
511 state_ = SEND_OLD_INITIAL_LOGS;
512 }
[email protected]d01b8732008-10-16 02:18:07513 recording_active_ = enabled;
initial.commit09911bf2008-07-26 23:55:29514}
515
[email protected]d01b8732008-10-16 02:18:07516bool MetricsService::recording_active() const {
initial.commit09911bf2008-07-26 23:55:29517 DCHECK(IsSingleThreaded());
[email protected]d01b8732008-10-16 02:18:07518 return recording_active_;
initial.commit09911bf2008-07-26 23:55:29519}
520
[email protected]d01b8732008-10-16 02:18:07521void MetricsService::SetReporting(bool enable) {
522 if (reporting_active_ != enable) {
523 reporting_active_ = enable;
524 if (reporting_active_)
[email protected]7f7f1962011-04-20 15:58:16525 StartSchedulerIfNecessary();
initial.commit09911bf2008-07-26 23:55:29526 }
[email protected]d01b8732008-10-16 02:18:07527}
528
529bool MetricsService::reporting_active() const {
530 DCHECK(IsSingleThreaded());
531 return reporting_active_;
initial.commit09911bf2008-07-26 23:55:29532}
533
[email protected]87ef9ea2011-02-26 03:15:15534// static
[email protected]3ffd3ae2011-03-17 22:17:52535void MetricsService::SetUpNotifications(NotificationRegistrar* registrar,
[email protected]87ef9ea2011-02-26 03:15:15536 NotificationObserver* observer) {
[email protected]432115822011-07-10 15:52:27537 registrar->Add(observer, chrome::NOTIFICATION_BROWSER_OPENED,
[email protected]87ef9ea2011-02-26 03:15:15538 NotificationService::AllSources());
[email protected]432115822011-07-10 15:52:27539 registrar->Add(observer, chrome::NOTIFICATION_BROWSER_CLOSED,
[email protected]87ef9ea2011-02-26 03:15:15540 NotificationService::AllSources());
[email protected]432115822011-07-10 15:52:27541 registrar->Add(observer, content::NOTIFICATION_USER_ACTION,
[email protected]87ef9ea2011-02-26 03:15:15542 NotificationService::AllSources());
[email protected]432115822011-07-10 15:52:27543 registrar->Add(observer, content::NOTIFICATION_TAB_PARENTED,
[email protected]87ef9ea2011-02-26 03:15:15544 NotificationService::AllSources());
[email protected]432115822011-07-10 15:52:27545 registrar->Add(observer, content::NOTIFICATION_TAB_CLOSING,
[email protected]87ef9ea2011-02-26 03:15:15546 NotificationService::AllSources());
[email protected]432115822011-07-10 15:52:27547 registrar->Add(observer, content::NOTIFICATION_LOAD_START,
[email protected]87ef9ea2011-02-26 03:15:15548 NotificationService::AllSources());
[email protected]432115822011-07-10 15:52:27549 registrar->Add(observer, content::NOTIFICATION_LOAD_STOP,
[email protected]87ef9ea2011-02-26 03:15:15550 NotificationService::AllSources());
[email protected]432115822011-07-10 15:52:27551 registrar->Add(observer, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
[email protected]87ef9ea2011-02-26 03:15:15552 NotificationService::AllSources());
[email protected]432115822011-07-10 15:52:27553 registrar->Add(observer, content::NOTIFICATION_RENDERER_PROCESS_HANG,
[email protected]87ef9ea2011-02-26 03:15:15554 NotificationService::AllSources());
[email protected]432115822011-07-10 15:52:27555 registrar->Add(observer, content::NOTIFICATION_CHILD_PROCESS_HOST_CONNECTED,
[email protected]87ef9ea2011-02-26 03:15:15556 NotificationService::AllSources());
[email protected]432115822011-07-10 15:52:27557 registrar->Add(observer, content::NOTIFICATION_CHILD_INSTANCE_CREATED,
[email protected]87ef9ea2011-02-26 03:15:15558 NotificationService::AllSources());
[email protected]432115822011-07-10 15:52:27559 registrar->Add(observer, content::NOTIFICATION_CHILD_PROCESS_CRASHED,
[email protected]87ef9ea2011-02-26 03:15:15560 NotificationService::AllSources());
[email protected]432115822011-07-10 15:52:27561 registrar->Add(observer, chrome::NOTIFICATION_TEMPLATE_URL_SERVICE_LOADED,
[email protected]87ef9ea2011-02-26 03:15:15562 NotificationService::AllSources());
[email protected]432115822011-07-10 15:52:27563 registrar->Add(observer, chrome::NOTIFICATION_OMNIBOX_OPENED_URL,
[email protected]87ef9ea2011-02-26 03:15:15564 NotificationService::AllSources());
[email protected]432115822011-07-10 15:52:27565 registrar->Add(observer, chrome::NOTIFICATION_BOOKMARK_MODEL_LOADED,
[email protected]2f35a312011-08-09 20:21:29566 NotificationService::AllBrowserContextsAndSources());
[email protected]87ef9ea2011-02-26 03:15:15567}
568
[email protected]432115822011-07-10 15:52:27569void MetricsService::Observe(int type,
initial.commit09911bf2008-07-26 23:55:29570 const NotificationSource& source,
571 const NotificationDetails& details) {
572 DCHECK(current_log_);
573 DCHECK(IsSingleThreaded());
574
575 if (!CanLogNotification(type, source, details))
576 return;
577
[email protected]432115822011-07-10 15:52:27578 switch (type) {
579 case content::NOTIFICATION_USER_ACTION:
[email protected]afe3a1672009-11-17 19:04:12580 current_log_->RecordUserAction(*Details<const char*>(details).ptr());
initial.commit09911bf2008-07-26 23:55:29581 break;
582
[email protected]432115822011-07-10 15:52:27583 case chrome::NOTIFICATION_BROWSER_OPENED:
584 case chrome::NOTIFICATION_BROWSER_CLOSED:
initial.commit09911bf2008-07-26 23:55:29585 LogWindowChange(type, source, details);
586 break;
587
[email protected]432115822011-07-10 15:52:27588 case content::NOTIFICATION_TAB_PARENTED:
589 case content::NOTIFICATION_TAB_CLOSING:
initial.commit09911bf2008-07-26 23:55:29590 LogWindowChange(type, source, details);
591 break;
592
[email protected]432115822011-07-10 15:52:27593 case content::NOTIFICATION_LOAD_STOP:
initial.commit09911bf2008-07-26 23:55:29594 LogLoadComplete(type, source, details);
595 break;
596
[email protected]432115822011-07-10 15:52:27597 case content::NOTIFICATION_LOAD_START:
initial.commit09911bf2008-07-26 23:55:29598 LogLoadStarted();
599 break;
600
[email protected]432115822011-07-10 15:52:27601 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: {
[email protected]cd69619b2010-05-05 02:41:38602 RenderProcessHost::RendererClosedDetails* process_details =
603 Details<RenderProcessHost::RendererClosedDetails>(details).ptr();
[email protected]443b80e2010-12-14 00:42:23604 if (process_details->status ==
605 base::TERMINATION_STATUS_PROCESS_CRASHED ||
606 process_details->status ==
607 base::TERMINATION_STATUS_ABNORMAL_TERMINATION) {
[email protected]cd69619b2010-05-05 02:41:38608 if (process_details->was_extension_renderer) {
609 LogExtensionRendererCrash();
610 } else {
611 LogRendererCrash();
612 }
613 }
[email protected]1f085622009-12-04 05:33:45614 }
initial.commit09911bf2008-07-26 23:55:29615 break;
616
[email protected]432115822011-07-10 15:52:27617 case content::NOTIFICATION_RENDERER_PROCESS_HANG:
initial.commit09911bf2008-07-26 23:55:29618 LogRendererHang();
619 break;
620
[email protected]432115822011-07-10 15:52:27621 case content::NOTIFICATION_CHILD_PROCESS_HOST_CONNECTED:
622 case content::NOTIFICATION_CHILD_PROCESS_CRASHED:
623 case content::NOTIFICATION_CHILD_INSTANCE_CREATED:
[email protected]a27a9382009-02-11 23:55:10624 LogChildProcessChange(type, source, details);
initial.commit09911bf2008-07-26 23:55:29625 break;
626
[email protected]432115822011-07-10 15:52:27627 case chrome::NOTIFICATION_TEMPLATE_URL_SERVICE_LOADED:
[email protected]8e5c89a2011-06-07 18:13:33628 LogKeywords(Source<TemplateURLService>(source).ptr());
initial.commit09911bf2008-07-26 23:55:29629 break;
630
[email protected]432115822011-07-10 15:52:27631 case chrome::NOTIFICATION_OMNIBOX_OPENED_URL: {
[email protected]1226abb2010-06-10 18:01:28632 MetricsLog* current_log = current_log_->AsMetricsLog();
633 DCHECK(current_log);
634 current_log->RecordOmniboxOpenedURL(
initial.commit09911bf2008-07-26 23:55:29635 *Details<AutocompleteLog>(details).ptr());
636 break;
[email protected]1226abb2010-06-10 18:01:28637 }
initial.commit09911bf2008-07-26 23:55:29638
[email protected]432115822011-07-10 15:52:27639 case chrome::NOTIFICATION_BOOKMARK_MODEL_LOADED: {
[email protected]b61236c62009-04-09 22:43:55640 Profile* p = Source<Profile>(source).ptr();
641 if (p)
642 LogBookmarks(p->GetBookmarkModel());
initial.commit09911bf2008-07-26 23:55:29643 break;
[email protected]b61236c62009-04-09 22:43:55644 }
initial.commit09911bf2008-07-26 23:55:29645 default:
[email protected]a063c102010-07-22 22:20:19646 NOTREACHED();
initial.commit09911bf2008-07-26 23:55:29647 break;
648 }
[email protected]d01b8732008-10-16 02:18:07649
650 HandleIdleSinceLastTransmission(false);
651
652 if (current_log_)
[email protected]666205032010-10-21 20:56:58653 DVLOG(1) << "METRICS: NUMBER OF EVENTS = " << current_log_->num_events();
[email protected]d01b8732008-10-16 02:18:07654}
655
656void MetricsService::HandleIdleSinceLastTransmission(bool in_idle) {
657 // If there wasn't a lot of action, maybe the computer was asleep, in which
658 // case, the log transmissions should have stopped. Here we start them up
659 // again.
[email protected]cac78842008-11-27 01:02:20660 if (!in_idle && idle_since_last_transmission_)
[email protected]7f7f1962011-04-20 15:58:16661 StartSchedulerIfNecessary();
[email protected]cac78842008-11-27 01:02:20662 idle_since_last_transmission_ = in_idle;
initial.commit09911bf2008-07-26 23:55:29663}
664
initial.commit09911bf2008-07-26 23:55:29665void MetricsService::RecordStartOfSessionEnd() {
[email protected]466f3c12011-03-23 21:20:38666 LogCleanShutdown();
initial.commit09911bf2008-07-26 23:55:29667 RecordBooleanPrefValue(prefs::kStabilitySessionEndCompleted, false);
668}
669
670void MetricsService::RecordCompletedSessionEnd() {
[email protected]466f3c12011-03-23 21:20:38671 LogCleanShutdown();
initial.commit09911bf2008-07-26 23:55:29672 RecordBooleanPrefValue(prefs::kStabilitySessionEndCompleted, true);
673}
674
[email protected]7f7f1962011-04-20 15:58:16675void MetricsService::RecordBreakpadRegistration(bool success) {
[email protected]68475e602008-08-22 03:21:15676 if (!success)
[email protected]e73c01972008-08-13 00:18:24677 IncrementPrefValue(prefs::kStabilityBreakpadRegistrationFail);
678 else
679 IncrementPrefValue(prefs::kStabilityBreakpadRegistrationSuccess);
680}
681
682void MetricsService::RecordBreakpadHasDebugger(bool has_debugger) {
683 if (!has_debugger)
684 IncrementPrefValue(prefs::kStabilityDebuggerNotPresent);
685 else
[email protected]68475e602008-08-22 03:21:15686 IncrementPrefValue(prefs::kStabilityDebuggerPresent);
[email protected]e73c01972008-08-13 00:18:24687}
688
initial.commit09911bf2008-07-26 23:55:29689//------------------------------------------------------------------------------
690// private methods
691//------------------------------------------------------------------------------
692
693
694//------------------------------------------------------------------------------
695// Initialization methods
696
697void MetricsService::InitializeMetricsState() {
[email protected]79bf0b72009-04-27 21:30:55698#if defined(OS_POSIX)
699 server_url_ = L"https://clients4.google.com/firefox/metrics/collect";
[email protected]d67d1052011-06-09 05:11:41700 // TODO(rtenneti): Return the network stats server name.
701 network_stats_server_ = "";
[email protected]79bf0b72009-04-27 21:30:55702#else
703 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
704 server_url_ = dist->GetStatsServerURL();
[email protected]d67d1052011-06-09 05:11:41705 network_stats_server_ = dist->GetNetworkStatsServer();
[email protected]79bf0b72009-04-27 21:30:55706#endif
707
initial.commit09911bf2008-07-26 23:55:29708 PrefService* pref = g_browser_process->local_state();
709 DCHECK(pref);
710
[email protected]225c50842010-01-19 21:19:13711 if ((pref->GetInt64(prefs::kStabilityStatsBuildTime)
712 != MetricsLog::GetBuildTime()) ||
[email protected]ddd231e2010-06-29 20:35:19713 (pref->GetString(prefs::kStabilityStatsVersion)
[email protected]225c50842010-01-19 21:19:13714 != MetricsLog::GetVersionString())) {
[email protected]541f77922009-02-23 21:14:38715 // This is a new version, so we don't want to confuse the stats about the
716 // old version with info that we upload.
717 DiscardOldStabilityStats(pref);
718 pref->SetString(prefs::kStabilityStatsVersion,
[email protected]ddd231e2010-06-29 20:35:19719 MetricsLog::GetVersionString());
[email protected]225c50842010-01-19 21:19:13720 pref->SetInt64(prefs::kStabilityStatsBuildTime,
721 MetricsLog::GetBuildTime());
[email protected]541f77922009-02-23 21:14:38722 }
723
initial.commit09911bf2008-07-26 23:55:29724 // Update session ID
725 session_id_ = pref->GetInteger(prefs::kMetricsSessionID);
726 ++session_id_;
727 pref->SetInteger(prefs::kMetricsSessionID, session_id_);
728
initial.commit09911bf2008-07-26 23:55:29729 // Stability bookkeeping
[email protected]e73c01972008-08-13 00:18:24730 IncrementPrefValue(prefs::kStabilityLaunchCount);
initial.commit09911bf2008-07-26 23:55:29731
[email protected]e73c01972008-08-13 00:18:24732 if (!pref->GetBoolean(prefs::kStabilityExitedCleanly)) {
733 IncrementPrefValue(prefs::kStabilityCrashCount);
initial.commit09911bf2008-07-26 23:55:29734 }
[email protected]e73c01972008-08-13 00:18:24735
736 // This will be set to 'true' if we exit cleanly.
initial.commit09911bf2008-07-26 23:55:29737 pref->SetBoolean(prefs::kStabilityExitedCleanly, false);
738
[email protected]e73c01972008-08-13 00:18:24739 if (!pref->GetBoolean(prefs::kStabilitySessionEndCompleted)) {
740 IncrementPrefValue(prefs::kStabilityIncompleteSessionEndCount);
[email protected]c9abf242009-07-18 06:00:38741 // This is marked false when we get a WM_ENDSESSION.
742 pref->SetBoolean(prefs::kStabilitySessionEndCompleted, true);
initial.commit09911bf2008-07-26 23:55:29743 }
initial.commit09911bf2008-07-26 23:55:29744
[email protected]9165f742010-03-10 22:55:01745 // Initialize uptime counters.
746 int64 startup_uptime = MetricsLog::GetIncrementalUptime(pref);
[email protected]ae393ec702010-06-27 16:23:14747 DCHECK_EQ(0, startup_uptime);
[email protected]9165f742010-03-10 22:55:01748 // For backwards compatibility, leave this intact in case Omaha is checking
749 // them. prefs::kStabilityLastTimestampSec may also be useless now.
750 // TODO(jar): Delete these if they have no uses.
[email protected]0bb1a622009-03-04 03:22:32751 pref->SetInt64(prefs::kStabilityLaunchTimeSec, Time::Now().ToTimeT());
752
753 // Bookkeeping for the uninstall metrics.
754 IncrementLongPrefsValue(prefs::kUninstallLaunchCount);
initial.commit09911bf2008-07-26 23:55:29755
756 // Save profile metrics.
757 PrefService* prefs = g_browser_process->local_state();
758 if (prefs) {
759 // Remove the current dictionary and store it for use when sending data to
760 // server. By removing the value we prune potentially dead profiles
761 // (and keys). All valid values are added back once services startup.
762 const DictionaryValue* profile_dictionary =
763 prefs->GetDictionary(prefs::kProfileMetrics);
764 if (profile_dictionary) {
765 // Do a deep copy of profile_dictionary since ClearPref will delete it.
766 profile_dictionary_.reset(static_cast<DictionaryValue*>(
767 profile_dictionary->DeepCopy()));
768 prefs->ClearPref(prefs::kProfileMetrics);
769 }
770 }
771
[email protected]92745242009-06-12 16:52:21772 // Get stats on use of command line.
773 const CommandLine* command_line(CommandLine::ForCurrentProcess());
774 size_t common_commands = 0;
775 if (command_line->HasSwitch(switches::kUserDataDir)) {
776 ++common_commands;
777 UMA_HISTOGRAM_COUNTS_100("Chrome.CommandLineDatDirCount", 1);
778 }
779
780 if (command_line->HasSwitch(switches::kApp)) {
781 ++common_commands;
782 UMA_HISTOGRAM_COUNTS_100("Chrome.CommandLineAppModeCount", 1);
783 }
784
[email protected]62b4e522011-07-13 21:46:32785 size_t switch_count = command_line->GetSwitches().size();
786 UMA_HISTOGRAM_COUNTS_100("Chrome.CommandLineFlagCount", switch_count);
[email protected]92745242009-06-12 16:52:21787 UMA_HISTOGRAM_COUNTS_100("Chrome.CommandLineUncommonFlagCount",
[email protected]62b4e522011-07-13 21:46:32788 switch_count - common_commands);
[email protected]92745242009-06-12 16:52:21789
initial.commit09911bf2008-07-26 23:55:29790 // Kick off the process of saving the state (so the uptime numbers keep
791 // getting updated) every n minutes.
792 ScheduleNextStateSave();
793}
794
[email protected]85ed9d42010-06-08 22:37:44795void MetricsService::OnInitTaskComplete(
796 const std::string& hardware_class,
[email protected]191eb3f72010-12-21 06:27:50797 const std::vector<webkit::npapi::WebPluginInfo>& plugins) {
[email protected]85ed9d42010-06-08 22:37:44798 DCHECK(state_ == INIT_TASK_SCHEDULED);
799 hardware_class_ = hardware_class;
[email protected]35fa6a22009-08-15 00:04:01800 plugins_ = plugins;
[email protected]d67d1052011-06-09 05:11:41801 io_thread_ = g_browser_process->io_thread();
[email protected]85ed9d42010-06-08 22:37:44802 if (state_ == INIT_TASK_SCHEDULED)
803 state_ = INIT_TASK_DONE;
initial.commit09911bf2008-07-26 23:55:29804}
805
806std::string MetricsService::GenerateClientID() {
[email protected]3469e7e2010-10-14 20:34:59807 return guid::GenerateGUID();
initial.commit09911bf2008-07-26 23:55:29808}
809
initial.commit09911bf2008-07-26 23:55:29810//------------------------------------------------------------------------------
811// State save methods
812
813void MetricsService::ScheduleNextStateSave() {
814 state_saver_factory_.RevokeAll();
815
816 MessageLoop::current()->PostDelayedTask(FROM_HERE,
817 state_saver_factory_.NewRunnableMethod(&MetricsService::SaveLocalState),
818 kSaveStateInterval * 1000);
819}
820
821void MetricsService::SaveLocalState() {
822 PrefService* pref = g_browser_process->local_state();
823 if (!pref) {
[email protected]a063c102010-07-22 22:20:19824 NOTREACHED();
initial.commit09911bf2008-07-26 23:55:29825 return;
826 }
827
828 RecordCurrentState(pref);
[email protected]6faa0e0d2009-04-28 06:50:36829 pref->ScheduleSavePersistentPrefs();
initial.commit09911bf2008-07-26 23:55:29830
[email protected]281d2882009-01-20 20:32:42831 // TODO(jar): Does this run down the batteries????
initial.commit09911bf2008-07-26 23:55:29832 ScheduleNextStateSave();
833}
834
835
836//------------------------------------------------------------------------------
837// Recording control methods
838
839void MetricsService::StartRecording() {
840 if (current_log_)
841 return;
842
843 current_log_ = new MetricsLog(client_id_, session_id_);
844 if (state_ == INITIALIZED) {
845 // We only need to schedule that run once.
[email protected]85ed9d42010-06-08 22:37:44846 state_ = INIT_TASK_SCHEDULED;
initial.commit09911bf2008-07-26 23:55:29847
[email protected]85ed9d42010-06-08 22:37:44848 // Schedules a task on the file thread for execution of slower
849 // initialization steps (such as plugin list generation) necessary
850 // for sending the initial log. This avoids blocking the main UI
851 // thread.
[email protected]7f2e792e2009-11-30 23:18:29852 g_browser_process->file_thread()->message_loop()->PostDelayedTask(FROM_HERE,
[email protected]85ed9d42010-06-08 22:37:44853 new InitTask(MessageLoop::current()),
[email protected]7f7f1962011-04-20 15:58:16854 kInitializationDelaySeconds * 1000);
initial.commit09911bf2008-07-26 23:55:29855 }
856}
857
[email protected]024b5cd2011-05-27 03:29:38858void MetricsService::StopRecording() {
initial.commit09911bf2008-07-26 23:55:29859 if (!current_log_)
860 return;
861
[email protected]49cd7e882011-02-01 03:54:36862 current_log_->set_hardware_class(hardware_class_); // Adds to ongoing logs.
[email protected]85ed9d42010-06-08 22:37:44863
[email protected]68475e602008-08-22 03:21:15864 // TODO(jar): Integrate bounds on log recording more consistently, so that we
865 // can stop recording logs that are too big much sooner.
[email protected]54702c92011-04-15 15:06:43866 if (current_log_->num_events() > kEventLimit) {
[email protected]553dba62009-02-24 19:08:23867 UMA_HISTOGRAM_COUNTS("UMA.Discarded Log Events",
[email protected]68475e602008-08-22 03:21:15868 current_log_->num_events());
869 current_log_->CloseLog();
870 delete current_log_;
[email protected]294638782008-09-24 00:22:41871 current_log_ = NULL;
[email protected]68475e602008-08-22 03:21:15872 StartRecording(); // Start trivial log to hold our histograms.
873 }
874
[email protected]0b33f80b2008-12-17 21:34:36875 // Put incremental data (histogram deltas, and realtime stats deltas) at the
[email protected]147bbc0b2009-01-06 19:37:40876 // end of all log transmissions (initial log handles this separately).
[email protected]024b5cd2011-05-27 03:29:38877 // RecordIncrementalStabilityElements only exists on the derived
878 // MetricsLog class.
879 MetricsLog* current_log = current_log_->AsMetricsLog();
880 DCHECK(current_log);
881 current_log->RecordIncrementalStabilityElements();
882 RecordCurrentHistograms();
initial.commit09911bf2008-07-26 23:55:29883
884 current_log_->CloseLog();
[email protected]024b5cd2011-05-27 03:29:38885 pending_log_ = current_log_;
initial.commit09911bf2008-07-26 23:55:29886 current_log_ = NULL;
887}
888
initial.commit09911bf2008-07-26 23:55:29889void MetricsService::PushPendingLogsToUnsentLists() {
890 if (state_ < INITIAL_LOG_READY)
[email protected]28ab7f92009-01-06 21:39:04891 return; // We didn't and still don't have time to get plugin list etc.
initial.commit09911bf2008-07-26 23:55:29892
893 if (pending_log()) {
894 PreparePendingLogText();
895 if (state_ == INITIAL_LOG_READY) {
896 // We may race here, and send second copy of initial log later.
[email protected]46f89e142010-07-19 08:00:42897 unsent_initial_logs_.push_back(compressed_log_);
[email protected]d01b8732008-10-16 02:18:07898 state_ = SEND_OLD_INITIAL_LOGS;
initial.commit09911bf2008-07-26 23:55:29899 } else {
[email protected]281d2882009-01-20 20:32:42900 // TODO(jar): Verify correctness in other states, including sending unsent
[email protected]541f77922009-02-23 21:14:38901 // initial logs.
[email protected]68475e602008-08-22 03:21:15902 PushPendingLogTextToUnsentOngoingLogs();
initial.commit09911bf2008-07-26 23:55:29903 }
904 DiscardPendingLog();
905 }
906 DCHECK(!pending_log());
[email protected]024b5cd2011-05-27 03:29:38907 StopRecording();
initial.commit09911bf2008-07-26 23:55:29908 PreparePendingLogText();
[email protected]68475e602008-08-22 03:21:15909 PushPendingLogTextToUnsentOngoingLogs();
initial.commit09911bf2008-07-26 23:55:29910 DiscardPendingLog();
911 StoreUnsentLogs();
912}
913
[email protected]68475e602008-08-22 03:21:15914void MetricsService::PushPendingLogTextToUnsentOngoingLogs() {
[email protected]46f89e142010-07-19 08:00:42915 if (compressed_log_.length() >
[email protected]dc6f4962009-02-13 01:25:50916 static_cast<size_t>(kUploadLogAvoidRetransmitSize)) {
[email protected]553dba62009-02-24 19:08:23917 UMA_HISTOGRAM_COUNTS("UMA.Large Accumulated Log Not Persisted",
[email protected]46f89e142010-07-19 08:00:42918 static_cast<int>(compressed_log_.length()));
[email protected]68475e602008-08-22 03:21:15919 return;
920 }
[email protected]46f89e142010-07-19 08:00:42921 unsent_ongoing_logs_.push_back(compressed_log_);
[email protected]68475e602008-08-22 03:21:15922}
923
initial.commit09911bf2008-07-26 23:55:29924//------------------------------------------------------------------------------
925// Transmission of logs methods
926
[email protected]7f7f1962011-04-20 15:58:16927void MetricsService::StartSchedulerIfNecessary() {
928 if (reporting_active() && recording_active())
929 scheduler_->Start();
initial.commit09911bf2008-07-26 23:55:29930}
931
[email protected]7f7f1962011-04-20 15:58:16932void MetricsService::StartScheduledUpload() {
933 // If reporting has been turned off, the scheduler doesn't need to run.
934 if (!reporting_active() || !recording_active()) {
935 scheduler_->Stop();
936 scheduler_->UploadCancelled();
937 return;
938 }
939
940 DCHECK(!waiting_for_asynchronus_reporting_step_);
941 waiting_for_asynchronus_reporting_step_ = true;
942
[email protected]84c988a2011-04-19 17:56:33943 Task* task = log_sender_factory_.
944 NewRunnableMethod(&MetricsService::OnMemoryDetailCollectionDone);
945
946 scoped_refptr<MetricsMemoryDetails> details(new MetricsMemoryDetails(task));
947 details->StartFetch();
948
949 // Collect WebCore cache information to put into a histogram.
950 for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator());
951 !i.IsAtEnd(); i.Advance())
952 i.GetCurrentValue()->Send(new ViewMsg_GetCacheResourceStats());
953}
954
955void MetricsService::OnMemoryDetailCollectionDone() {
[email protected]c9a3ef82009-05-28 22:02:46956 DCHECK(IsSingleThreaded());
[email protected]7f7f1962011-04-20 15:58:16957 // This function should only be called as the callback from an ansynchronous
958 // step.
959 DCHECK(waiting_for_asynchronus_reporting_step_);
[email protected]c9a3ef82009-05-28 22:02:46960
[email protected]7f7f1962011-04-20 15:58:16961 // Right before the UMA transmission gets started, there's one more thing we'd
962 // like to record: the histogram of memory usage, so we spawn a task to
963 // collect the memory details and when that task is finished, it will call
964 // OnMemoryDetailCollectionDone, which will call HistogramSynchronization to
965 // collect histograms from all renderers and then we will call
966 // OnHistogramSynchronizationDone to continue processing.
[email protected]c9a3ef82009-05-28 22:02:46967
968 // Create a callback_task for OnHistogramSynchronizationDone.
969 Task* callback_task = log_sender_factory_.NewRunnableMethod(
970 &MetricsService::OnHistogramSynchronizationDone);
971
972 // Set up the callback to task to call after we receive histograms from all
973 // renderer processes. Wait time specifies how long to wait before absolutely
974 // calling us back on the task.
975 HistogramSynchronizer::FetchRendererHistogramsAsynchronously(
976 MessageLoop::current(), callback_task,
977 kMaxHistogramGatheringWaitDuration);
978}
979
980void MetricsService::OnHistogramSynchronizationDone() {
initial.commit09911bf2008-07-26 23:55:29981 DCHECK(IsSingleThreaded());
982
[email protected]7f7f1962011-04-20 15:58:16983 // If somehow there is a fetch in progress, we return and hope things work
984 // out. The scheduler isn't informed since if this happens, the scheduler
985 // will get a response from the upload.
initial.commit09911bf2008-07-26 23:55:29986 DCHECK(!current_fetch_.get());
[email protected]7f7f1962011-04-20 15:58:16987 if (current_fetch_.get())
988 return;
989
990 // This function should only be called as the callback from an ansynchronous
991 // step.
992 DCHECK(waiting_for_asynchronus_reporting_step_);
993 waiting_for_asynchronus_reporting_step_ = false;
initial.commit09911bf2008-07-26 23:55:29994
[email protected]d01b8732008-10-16 02:18:07995 // If we're getting no notifications, then the log won't have much in it, and
996 // it's possible the computer is about to go to sleep, so don't upload and
[email protected]7f7f1962011-04-20 15:58:16997 // stop the scheduler.
998 // Similarly, if logs should no longer be uploaded, stop here.
999 if (idle_since_last_transmission_ ||
1000 !recording_active() || !reporting_active()) {
1001 scheduler_->Stop();
1002 scheduler_->UploadCancelled();
[email protected]d01b8732008-10-16 02:18:071003 return;
1004 }
1005
[email protected]d01b8732008-10-16 02:18:071006 MakePendingLog();
initial.commit09911bf2008-07-26 23:55:291007
[email protected]d01b8732008-10-16 02:18:071008 // MakePendingLog should have put something in the pending log, if it didn't,
[email protected]7f7f1962011-04-20 15:58:161009 // we skip this upload and hope things work out next time.
[email protected]d01b8732008-10-16 02:18:071010 if (!pending_log()) {
[email protected]7f7f1962011-04-20 15:58:161011 scheduler_->UploadCancelled();
[email protected]d01b8732008-10-16 02:18:071012 return;
1013 }
initial.commit09911bf2008-07-26 23:55:291014
[email protected]d01b8732008-10-16 02:18:071015 PrepareFetchWithPendingLog();
1016
1017 if (!current_fetch_.get()) {
1018 // Compression failed, and log discarded :-/.
1019 DiscardPendingLog();
[email protected]7f7f1962011-04-20 15:58:161020 scheduler_->UploadCancelled();
[email protected]d01b8732008-10-16 02:18:071021 // TODO(jar): If compression failed, we should have created a tiny log and
1022 // compressed that, so that we can signal that we're losing logs.
1023 return;
1024 }
1025
[email protected]7f7f1962011-04-20 15:58:161026 DCHECK(!waiting_for_asynchronus_reporting_step_);
[email protected]d01b8732008-10-16 02:18:071027
[email protected]7f7f1962011-04-20 15:58:161028 waiting_for_asynchronus_reporting_step_ = true;
[email protected]d01b8732008-10-16 02:18:071029 current_fetch_->Start();
1030
1031 HandleIdleSinceLastTransmission(true);
1032}
1033
1034
1035void MetricsService::MakePendingLog() {
1036 if (pending_log())
1037 return;
1038
1039 switch (state_) {
1040 case INITIALIZED:
[email protected]85ed9d42010-06-08 22:37:441041 case INIT_TASK_SCHEDULED: // We should be further along by now.
[email protected]d01b8732008-10-16 02:18:071042 DCHECK(false);
1043 return;
1044
[email protected]85ed9d42010-06-08 22:37:441045 case INIT_TASK_DONE:
[email protected]d01b8732008-10-16 02:18:071046 // We need to wait for the initial log to be ready before sending
1047 // anything, because the server will tell us whether it wants to hear
1048 // from us.
1049 PrepareInitialLog();
[email protected]85ed9d42010-06-08 22:37:441050 DCHECK(state_ == INIT_TASK_DONE);
[email protected]d01b8732008-10-16 02:18:071051 RecallUnsentLogs();
1052 state_ = INITIAL_LOG_READY;
1053 break;
1054
1055 case SEND_OLD_INITIAL_LOGS:
[email protected]cac78842008-11-27 01:02:201056 if (!unsent_initial_logs_.empty()) {
[email protected]46f89e142010-07-19 08:00:421057 compressed_log_ = unsent_initial_logs_.back();
[email protected]d53e2232011-06-30 15:54:571058 unsent_initial_logs_.pop_back();
[email protected]cac78842008-11-27 01:02:201059 break;
1060 }
[email protected]d01b8732008-10-16 02:18:071061 state_ = SENDING_OLD_LOGS;
1062 // Fall through.
initial.commit09911bf2008-07-26 23:55:291063
[email protected]d01b8732008-10-16 02:18:071064 case SENDING_OLD_LOGS:
1065 if (!unsent_ongoing_logs_.empty()) {
[email protected]46f89e142010-07-19 08:00:421066 compressed_log_ = unsent_ongoing_logs_.back();
[email protected]d53e2232011-06-30 15:54:571067 unsent_ongoing_logs_.pop_back();
[email protected]d01b8732008-10-16 02:18:071068 break;
1069 }
1070 state_ = SENDING_CURRENT_LOGS;
1071 // Fall through.
1072
1073 case SENDING_CURRENT_LOGS:
[email protected]024b5cd2011-05-27 03:29:381074 StopRecording();
[email protected]d01b8732008-10-16 02:18:071075 StartRecording();
1076 break;
1077
1078 default:
[email protected]a063c102010-07-22 22:20:191079 NOTREACHED();
[email protected]d01b8732008-10-16 02:18:071080 return;
1081 }
1082
1083 DCHECK(pending_log());
1084}
1085
initial.commit09911bf2008-07-26 23:55:291086void MetricsService::PrepareInitialLog() {
[email protected]85ed9d42010-06-08 22:37:441087 DCHECK(state_ == INIT_TASK_DONE);
initial.commit09911bf2008-07-26 23:55:291088
1089 MetricsLog* log = new MetricsLog(client_id_, session_id_);
[email protected]85ed9d42010-06-08 22:37:441090 log->set_hardware_class(hardware_class_); // Adds to initial log.
[email protected]35fa6a22009-08-15 00:04:011091 log->RecordEnvironment(plugins_, profile_dictionary_.get());
initial.commit09911bf2008-07-26 23:55:291092
1093 // Histograms only get written to current_log_, so setup for the write.
[email protected]1226abb2010-06-10 18:01:281094 MetricsLogBase* save_log = current_log_;
initial.commit09911bf2008-07-26 23:55:291095 current_log_ = log;
1096 RecordCurrentHistograms(); // Into current_log_... which is really log.
1097 current_log_ = save_log;
1098
1099 log->CloseLog();
1100 DCHECK(!pending_log());
1101 pending_log_ = log;
1102}
1103
[email protected]46f89e142010-07-19 08:00:421104// static
1105MetricsService::LogRecallStatus MetricsService::RecallUnsentLogsHelper(
1106 const ListValue& list,
1107 std::vector<std::string>* local_list) {
1108 DCHECK(local_list->empty());
1109 if (list.GetSize() == 0)
1110 return MakeRecallStatusHistogram(LIST_EMPTY);
1111 if (list.GetSize() < 3)
1112 return MakeRecallStatusHistogram(LIST_SIZE_TOO_SMALL);
initial.commit09911bf2008-07-26 23:55:291113
[email protected]46f89e142010-07-19 08:00:421114 // The size is stored at the beginning of the list.
1115 int size;
1116 bool valid = (*list.begin())->GetAsInteger(&size);
1117 if (!valid)
1118 return MakeRecallStatusHistogram(LIST_SIZE_MISSING);
1119
1120 // Account for checksum and size included in the list.
1121 if (static_cast<unsigned int>(size) !=
1122 list.GetSize() - kChecksumEntryCount)
1123 return MakeRecallStatusHistogram(LIST_SIZE_CORRUPTION);
1124
[email protected]0ad1d2d62011-07-18 16:54:581125 base::MD5Context ctx;
1126 base::MD5Init(&ctx);
[email protected]46f89e142010-07-19 08:00:421127 std::string encoded_log;
1128 std::string decoded_log;
1129 for (ListValue::const_iterator it = list.begin() + 1;
1130 it != list.end() - 1; ++it) { // Last element is the checksum.
1131 valid = (*it)->GetAsString(&encoded_log);
1132 if (!valid) {
1133 local_list->clear();
1134 return MakeRecallStatusHistogram(LOG_STRING_CORRUPTION);
1135 }
1136
[email protected]a3bcff62011-07-26 23:39:501137 base::MD5Update(&ctx, encoded_log);
[email protected]46f89e142010-07-19 08:00:421138
1139 if (!base::Base64Decode(encoded_log, &decoded_log)) {
1140 local_list->clear();
1141 return MakeRecallStatusHistogram(DECODE_FAIL);
1142 }
1143 local_list->push_back(decoded_log);
1144 }
1145
1146 // Verify checksum.
[email protected]0ad1d2d62011-07-18 16:54:581147 base::MD5Digest digest;
1148 base::MD5Final(&digest, &ctx);
[email protected]46f89e142010-07-19 08:00:421149 std::string recovered_md5;
1150 // We store the hash at the end of the list.
1151 valid = (*(list.end() - 1))->GetAsString(&recovered_md5);
1152 if (!valid) {
1153 local_list->clear();
1154 return MakeRecallStatusHistogram(CHECKSUM_STRING_CORRUPTION);
1155 }
[email protected]0ad1d2d62011-07-18 16:54:581156 if (recovered_md5 != base::MD5DigestToBase16(digest)) {
[email protected]46f89e142010-07-19 08:00:421157 local_list->clear();
1158 return MakeRecallStatusHistogram(CHECKSUM_CORRUPTION);
1159 }
1160 return MakeRecallStatusHistogram(RECALL_SUCCESS);
1161}
1162void MetricsService::RecallUnsentLogs() {
initial.commit09911bf2008-07-26 23:55:291163 PrefService* local_state = g_browser_process->local_state();
1164 DCHECK(local_state);
1165
[email protected]f8628c22011-04-05 12:10:181166 const ListValue* unsent_initial_logs = local_state->GetList(
initial.commit09911bf2008-07-26 23:55:291167 prefs::kMetricsInitialLogs);
[email protected]46f89e142010-07-19 08:00:421168 RecallUnsentLogsHelper(*unsent_initial_logs, &unsent_initial_logs_);
initial.commit09911bf2008-07-26 23:55:291169
[email protected]f8628c22011-04-05 12:10:181170 const ListValue* unsent_ongoing_logs = local_state->GetList(
initial.commit09911bf2008-07-26 23:55:291171 prefs::kMetricsOngoingLogs);
[email protected]46f89e142010-07-19 08:00:421172 RecallUnsentLogsHelper(*unsent_ongoing_logs, &unsent_ongoing_logs_);
1173}
1174
1175// static
1176void MetricsService::StoreUnsentLogsHelper(
1177 const std::vector<std::string>& local_list,
1178 const size_t kMaxLocalListSize,
1179 ListValue* list) {
1180 list->Clear();
1181 size_t start = 0;
1182 if (local_list.size() > kMaxLocalListSize)
1183 start = local_list.size() - kMaxLocalListSize;
1184 DCHECK(start <= local_list.size());
1185 if (local_list.size() == start)
1186 return;
1187
1188 // Store size at the beginning of the list.
1189 list->Append(Value::CreateIntegerValue(local_list.size() - start));
1190
[email protected]0ad1d2d62011-07-18 16:54:581191 base::MD5Context ctx;
1192 base::MD5Init(&ctx);
[email protected]46f89e142010-07-19 08:00:421193 std::string encoded_log;
1194 for (std::vector<std::string>::const_iterator it = local_list.begin() + start;
1195 it != local_list.end(); ++it) {
1196 // We encode the compressed log as Value::CreateStringValue() expects to
1197 // take a valid UTF8 string.
1198 if (!base::Base64Encode(*it, &encoded_log)) {
1199 MakeStoreStatusHistogram(ENCODE_FAIL);
1200 list->Clear();
1201 return;
1202 }
[email protected]a3bcff62011-07-26 23:39:501203 base::MD5Update(&ctx, encoded_log);
[email protected]46f89e142010-07-19 08:00:421204 list->Append(Value::CreateStringValue(encoded_log));
initial.commit09911bf2008-07-26 23:55:291205 }
[email protected]46f89e142010-07-19 08:00:421206
1207 // Append hash to the end of the list.
[email protected]0ad1d2d62011-07-18 16:54:581208 base::MD5Digest digest;
1209 base::MD5Final(&digest, &ctx);
1210 list->Append(Value::CreateStringValue(base::MD5DigestToBase16(digest)));
[email protected]46f89e142010-07-19 08:00:421211 DCHECK(list->GetSize() >= 3); // Minimum of 3 elements (size, data, hash).
[email protected]4e95d202010-07-24 01:47:561212 MakeStoreStatusHistogram(STORE_SUCCESS);
initial.commit09911bf2008-07-26 23:55:291213}
1214
1215void MetricsService::StoreUnsentLogs() {
1216 if (state_ < INITIAL_LOG_READY)
1217 return; // We never Recalled the prior unsent logs.
1218
1219 PrefService* local_state = g_browser_process->local_state();
1220 DCHECK(local_state);
1221
[email protected]f8628c22011-04-05 12:10:181222 {
1223 ListPrefUpdate update(local_state, prefs::kMetricsInitialLogs);
1224 ListValue* unsent_initial_logs = update.Get();
1225 StoreUnsentLogsHelper(unsent_initial_logs_, kMaxInitialLogsPersisted,
1226 unsent_initial_logs);
1227 }
initial.commit09911bf2008-07-26 23:55:291228
[email protected]f8628c22011-04-05 12:10:181229 {
1230 ListPrefUpdate update(local_state, prefs::kMetricsOngoingLogs);
1231 ListValue* unsent_ongoing_logs = update.Get();
1232 StoreUnsentLogsHelper(unsent_ongoing_logs_, kMaxOngoingLogsPersisted,
1233 unsent_ongoing_logs);
1234 }
initial.commit09911bf2008-07-26 23:55:291235}
1236
1237void MetricsService::PreparePendingLogText() {
1238 DCHECK(pending_log());
[email protected]46f89e142010-07-19 08:00:421239 if (!compressed_log_.empty())
initial.commit09911bf2008-07-26 23:55:291240 return;
[email protected]9ffcccf42009-09-15 22:19:181241 int text_size = pending_log_->GetEncodedLogSize();
1242
[email protected]46f89e142010-07-19 08:00:421243 std::string pending_log_text;
1244 // Leave room for the NULL terminator.
1245 pending_log_->GetEncodedLog(WriteInto(&pending_log_text, text_size + 1),
[email protected]9ffcccf42009-09-15 22:19:181246 text_size);
[email protected]46f89e142010-07-19 08:00:421247
1248 if (Bzip2Compress(pending_log_text, &compressed_log_)) {
1249 // Allow security conscious users to see all metrics logs that we send.
[email protected]666205032010-10-21 20:56:581250 VLOG(1) << "COMPRESSED FOLLOWING METRICS LOG: " << pending_log_text;
[email protected]46f89e142010-07-19 08:00:421251 } else {
1252 LOG(DFATAL) << "Failed to compress log for transmission.";
1253 // We can't discard the logs as other caller functions expect that
1254 // |compressed_log_| not be empty. We can detect this failure at the server
1255 // after we transmit.
1256 compressed_log_ = "Unable to compress!";
1257 MakeStoreStatusHistogram(COMPRESS_FAIL);
1258 return;
1259 }
initial.commit09911bf2008-07-26 23:55:291260}
1261
[email protected]d01b8732008-10-16 02:18:071262void MetricsService::PrepareFetchWithPendingLog() {
initial.commit09911bf2008-07-26 23:55:291263 DCHECK(pending_log());
1264 DCHECK(!current_fetch_.get());
1265 PreparePendingLogText();
[email protected]46f89e142010-07-19 08:00:421266 DCHECK(!compressed_log_.empty());
[email protected]cac78842008-11-27 01:02:201267
[email protected]79bf0b72009-04-27 21:30:551268 current_fetch_.reset(new URLFetcher(GURL(WideToUTF16(server_url_)),
1269 URLFetcher::POST,
initial.commit09911bf2008-07-26 23:55:291270 this));
[email protected]9abfa192011-07-20 15:48:531271 current_fetch_->set_request_context(
[email protected]8ef3d8052011-07-22 09:03:001272 g_browser_process->system_request_context());
[email protected]46f89e142010-07-19 08:00:421273 current_fetch_->set_upload_data(kMetricsType, compressed_log_);
initial.commit09911bf2008-07-26 23:55:291274}
1275
[email protected]f90bf0d92011-01-13 02:12:441276static const char* StatusToString(const net::URLRequestStatus& status) {
initial.commit09911bf2008-07-26 23:55:291277 switch (status.status()) {
[email protected]f90bf0d92011-01-13 02:12:441278 case net::URLRequestStatus::SUCCESS:
initial.commit09911bf2008-07-26 23:55:291279 return "SUCCESS";
1280
[email protected]f90bf0d92011-01-13 02:12:441281 case net::URLRequestStatus::IO_PENDING:
initial.commit09911bf2008-07-26 23:55:291282 return "IO_PENDING";
1283
[email protected]f90bf0d92011-01-13 02:12:441284 case net::URLRequestStatus::HANDLED_EXTERNALLY:
initial.commit09911bf2008-07-26 23:55:291285 return "HANDLED_EXTERNALLY";
1286
[email protected]f90bf0d92011-01-13 02:12:441287 case net::URLRequestStatus::CANCELED:
initial.commit09911bf2008-07-26 23:55:291288 return "CANCELED";
1289
[email protected]f90bf0d92011-01-13 02:12:441290 case net::URLRequestStatus::FAILED:
initial.commit09911bf2008-07-26 23:55:291291 return "FAILED";
1292
1293 default:
[email protected]a063c102010-07-22 22:20:191294 NOTREACHED();
initial.commit09911bf2008-07-26 23:55:291295 return "Unknown";
1296 }
1297}
1298
1299void MetricsService::OnURLFetchComplete(const URLFetcher* source,
1300 const GURL& url,
[email protected]f90bf0d92011-01-13 02:12:441301 const net::URLRequestStatus& status,
initial.commit09911bf2008-07-26 23:55:291302 int response_code,
[email protected]cb04f5e2011-05-06 01:10:001303 const net::ResponseCookies& cookies,
initial.commit09911bf2008-07-26 23:55:291304 const std::string& data) {
[email protected]7f7f1962011-04-20 15:58:161305 DCHECK(waiting_for_asynchronus_reporting_step_);
1306 waiting_for_asynchronus_reporting_step_ = false;
initial.commit09911bf2008-07-26 23:55:291307 DCHECK(current_fetch_.get());
1308 current_fetch_.reset(NULL); // We're not allowed to re-use it.
1309
1310 // Confirm send so that we can move on.
[email protected]666205032010-10-21 20:56:581311 VLOG(1) << "METRICS RESPONSE CODE: " << response_code
1312 << " status=" << StatusToString(status);
[email protected]252873ef2008-08-04 21:59:451313
[email protected]7f7f1962011-04-20 15:58:161314 bool upload_succeeded = response_code == 200;
1315
[email protected]0eb34fee2009-01-21 08:04:381316 // Provide boolean for error recovery (allow us to ignore response_code).
[email protected]dc6f4962009-02-13 01:25:501317 bool discard_log = false;
[email protected]0eb34fee2009-01-21 08:04:381318
[email protected]7f7f1962011-04-20 15:58:161319 if (!upload_succeeded &&
[email protected]46f89e142010-07-19 08:00:421320 (compressed_log_.length() >
1321 static_cast<size_t>(kUploadLogAvoidRetransmitSize))) {
[email protected]553dba62009-02-24 19:08:231322 UMA_HISTOGRAM_COUNTS("UMA.Large Rejected Log was Discarded",
[email protected]46f89e142010-07-19 08:00:421323 static_cast<int>(compressed_log_.length()));
[email protected]0eb34fee2009-01-21 08:04:381324 discard_log = true;
1325 } else if (response_code == 400) {
1326 // Bad syntax. Retransmission won't work.
[email protected]553dba62009-02-24 19:08:231327 UMA_HISTOGRAM_COUNTS("UMA.Unacceptable_Log_Discarded", state_);
[email protected]0eb34fee2009-01-21 08:04:381328 discard_log = true;
[email protected]68475e602008-08-22 03:21:151329 }
1330
[email protected]7f7f1962011-04-20 15:58:161331 if (!upload_succeeded && !discard_log) {
[email protected]666205032010-10-21 20:56:581332 VLOG(1) << "METRICS: transmission attempt returned a failure code: "
1333 << response_code << ". Verify network connectivity";
[email protected]7f7f1962011-04-20 15:58:161334 LogBadResponseCode();
[email protected]0eb34fee2009-01-21 08:04:381335 } else { // Successful receipt (or we are discarding log).
[email protected]666205032010-10-21 20:56:581336 VLOG(1) << "METRICS RESPONSE DATA: " << data;
initial.commit09911bf2008-07-26 23:55:291337 switch (state_) {
1338 case INITIAL_LOG_READY:
1339 state_ = SEND_OLD_INITIAL_LOGS;
1340 break;
1341
1342 case SEND_OLD_INITIAL_LOGS:
initial.commit09911bf2008-07-26 23:55:291343 case SENDING_OLD_LOGS:
[email protected]d53e2232011-06-30 15:54:571344 // Store the updated list to disk now that the removed log is uploaded.
initial.commit09911bf2008-07-26 23:55:291345 StoreUnsentLogs();
1346 break;
1347
1348 case SENDING_CURRENT_LOGS:
1349 break;
1350
1351 default:
[email protected]a063c102010-07-22 22:20:191352 NOTREACHED();
initial.commit09911bf2008-07-26 23:55:291353 break;
1354 }
[email protected]d01b8732008-10-16 02:18:071355
initial.commit09911bf2008-07-26 23:55:291356 DiscardPendingLog();
[email protected]29be92552008-08-07 22:49:271357 // Since we sent a log, make sure our in-memory state is recorded to disk.
1358 PrefService* local_state = g_browser_process->local_state();
1359 DCHECK(local_state);
1360 if (local_state)
[email protected]6faa0e0d2009-04-28 06:50:361361 local_state->ScheduleSavePersistentPrefs();
[email protected]252873ef2008-08-04 21:59:451362
[email protected]7f7f1962011-04-20 15:58:161363 if (unsent_logs())
initial.commit09911bf2008-07-26 23:55:291364 DCHECK(state_ < SENDING_CURRENT_LOGS);
initial.commit09911bf2008-07-26 23:55:291365 }
[email protected]252873ef2008-08-04 21:59:451366
[email protected]7f7f1962011-04-20 15:58:161367 // Error 400 indicates a problem with the log, not with the server, so
1368 // don't consider that a sign that the server is in trouble.
1369 bool server_is_healthy = upload_succeeded || response_code == 400;
1370
1371 scheduler_->UploadFinished(server_is_healthy, unsent_logs());
[email protected]d67d1052011-06-09 05:11:411372
1373 // Collect network stats if UMA upload succeeded.
1374 if (server_is_healthy && io_thread_)
1375 chrome_browser_net::CollectNetworkStats(network_stats_server_, io_thread_);
initial.commit09911bf2008-07-26 23:55:291376}
1377
[email protected]7f7f1962011-04-20 15:58:161378void MetricsService::LogBadResponseCode() {
[email protected]666205032010-10-21 20:56:581379 VLOG(1) << "Verify your metrics logs are formatted correctly. Verify server "
1380 "is active at " << server_url_;
[email protected]252873ef2008-08-04 21:59:451381 if (!pending_log()) {
[email protected]666205032010-10-21 20:56:581382 VLOG(1) << "METRICS: Recorder shutdown during log transmission.";
[email protected]252873ef2008-08-04 21:59:451383 } else {
[email protected]7f7f1962011-04-20 15:58:161384 VLOG(1) << "METRICS: transmission retry being scheduled for "
[email protected]666205032010-10-21 20:56:581385 << compressed_log_;
initial.commit09911bf2008-07-26 23:55:291386 }
initial.commit09911bf2008-07-26 23:55:291387}
1388
[email protected]432115822011-07-10 15:52:271389void MetricsService::LogWindowChange(int type,
initial.commit09911bf2008-07-26 23:55:291390 const NotificationSource& source,
1391 const NotificationDetails& details) {
[email protected]534e54b2008-08-13 15:40:091392 int controller_id = -1;
1393 uintptr_t window_or_tab = source.map_key();
initial.commit09911bf2008-07-26 23:55:291394 MetricsLog::WindowEventType window_type;
1395
1396 // Note: since we stop all logging when a single OTR session is active, it is
1397 // possible that we start getting notifications about a window that we don't
1398 // know about.
[email protected]534e54b2008-08-13 15:40:091399 if (window_map_.find(window_or_tab) == window_map_.end()) {
1400 controller_id = next_window_id_++;
1401 window_map_[window_or_tab] = controller_id;
initial.commit09911bf2008-07-26 23:55:291402 } else {
[email protected]534e54b2008-08-13 15:40:091403 controller_id = window_map_[window_or_tab];
initial.commit09911bf2008-07-26 23:55:291404 }
[email protected]92745242009-06-12 16:52:211405 DCHECK_NE(controller_id, -1);
initial.commit09911bf2008-07-26 23:55:291406
[email protected]432115822011-07-10 15:52:271407 switch (type) {
1408 case content::NOTIFICATION_TAB_PARENTED:
1409 case chrome::NOTIFICATION_BROWSER_OPENED:
initial.commit09911bf2008-07-26 23:55:291410 window_type = MetricsLog::WINDOW_CREATE;
1411 break;
1412
[email protected]432115822011-07-10 15:52:271413 case content::NOTIFICATION_TAB_CLOSING:
1414 case chrome::NOTIFICATION_BROWSER_CLOSED:
[email protected]534e54b2008-08-13 15:40:091415 window_map_.erase(window_map_.find(window_or_tab));
initial.commit09911bf2008-07-26 23:55:291416 window_type = MetricsLog::WINDOW_DESTROY;
1417 break;
1418
1419 default:
[email protected]a063c102010-07-22 22:20:191420 NOTREACHED();
[email protected]68d74f02009-02-13 01:36:501421 return;
initial.commit09911bf2008-07-26 23:55:291422 }
1423
[email protected]534e54b2008-08-13 15:40:091424 // TODO(brettw) we should have some kind of ID for the parent.
1425 current_log_->RecordWindowEvent(window_type, controller_id, 0);
initial.commit09911bf2008-07-26 23:55:291426}
1427
[email protected]432115822011-07-10 15:52:271428void MetricsService::LogLoadComplete(int type,
initial.commit09911bf2008-07-26 23:55:291429 const NotificationSource& source,
1430 const NotificationDetails& details) {
1431 if (details == NotificationService::NoDetails())
1432 return;
1433
[email protected]68475e602008-08-22 03:21:151434 // TODO(jar): There is a bug causing this to be called too many times, and
1435 // the log overflows. For now, we won't record these events.
[email protected]553dba62009-02-24 19:08:231436 UMA_HISTOGRAM_COUNTS("UMA.LogLoadComplete called", 1);
[email protected]68475e602008-08-22 03:21:151437 return;
1438
initial.commit09911bf2008-07-26 23:55:291439 const Details<LoadNotificationDetails> load_details(details);
[email protected]534e54b2008-08-13 15:40:091440 int controller_id = window_map_[details.map_key()];
1441 current_log_->RecordLoadEvent(controller_id,
initial.commit09911bf2008-07-26 23:55:291442 load_details->url(),
1443 load_details->origin(),
1444 load_details->session_index(),
1445 load_details->load_time());
1446}
1447
[email protected]57ecc4b2010-08-11 03:02:511448void MetricsService::IncrementPrefValue(const char* path) {
[email protected]e73c01972008-08-13 00:18:241449 PrefService* pref = g_browser_process->local_state();
1450 DCHECK(pref);
1451 int value = pref->GetInteger(path);
1452 pref->SetInteger(path, value + 1);
1453}
1454
[email protected]57ecc4b2010-08-11 03:02:511455void MetricsService::IncrementLongPrefsValue(const char* path) {
[email protected]0bb1a622009-03-04 03:22:321456 PrefService* pref = g_browser_process->local_state();
1457 DCHECK(pref);
1458 int64 value = pref->GetInt64(path);
[email protected]b42c5e42010-06-03 20:43:251459 pref->SetInt64(path, value + 1);
[email protected]0bb1a622009-03-04 03:22:321460}
1461
initial.commit09911bf2008-07-26 23:55:291462void MetricsService::LogLoadStarted() {
[email protected]e73c01972008-08-13 00:18:241463 IncrementPrefValue(prefs::kStabilityPageLoadCount);
[email protected]0bb1a622009-03-04 03:22:321464 IncrementLongPrefsValue(prefs::kUninstallMetricsPageLoadCount);
[email protected]0b33f80b2008-12-17 21:34:361465 // We need to save the prefs, as page load count is a critical stat, and it
1466 // might be lost due to a crash :-(.
initial.commit09911bf2008-07-26 23:55:291467}
1468
initial.commit09911bf2008-07-26 23:55:291469void MetricsService::LogRendererCrash() {
[email protected]e73c01972008-08-13 00:18:241470 IncrementPrefValue(prefs::kStabilityRendererCrashCount);
initial.commit09911bf2008-07-26 23:55:291471}
1472
[email protected]1f085622009-12-04 05:33:451473void MetricsService::LogExtensionRendererCrash() {
1474 IncrementPrefValue(prefs::kStabilityExtensionRendererCrashCount);
1475}
1476
initial.commit09911bf2008-07-26 23:55:291477void MetricsService::LogRendererHang() {
[email protected]e73c01972008-08-13 00:18:241478 IncrementPrefValue(prefs::kStabilityRendererHangCount);
initial.commit09911bf2008-07-26 23:55:291479}
1480
[email protected]466f3c12011-03-23 21:20:381481void MetricsService::LogCleanShutdown() {
1482 RecordBooleanPrefValue(prefs::kStabilityExitedCleanly, true);
1483}
1484
[email protected]c1834a92011-01-21 18:21:031485#if defined(OS_CHROMEOS)
1486void MetricsService::LogChromeOSCrash(const std::string &crash_type) {
1487 if (crash_type == "user")
1488 IncrementPrefValue(prefs::kStabilityOtherUserCrashCount);
1489 else if (crash_type == "kernel")
1490 IncrementPrefValue(prefs::kStabilityKernelCrashCount);
1491 else if (crash_type == "uncleanshutdown")
1492 IncrementPrefValue(prefs::kStabilitySystemUncleanShutdownCount);
1493 else
1494 NOTREACHED() << "Unexpected Chrome OS crash type " << crash_type;
1495 // Wake up metrics logs sending if necessary now that new
1496 // log data is available.
1497 HandleIdleSinceLastTransmission(false);
1498}
1499#endif // OS_CHROMEOS
1500
[email protected]a27a9382009-02-11 23:55:101501void MetricsService::LogChildProcessChange(
[email protected]432115822011-07-10 15:52:271502 int type,
[email protected]a27a9382009-02-11 23:55:101503 const NotificationSource& source,
1504 const NotificationDetails& details) {
[email protected]0d84c5d2009-10-09 01:10:421505 Details<ChildProcessInfo> child_details(details);
[email protected]68b9e72b2011-08-05 23:08:221506 const string16& child_name = child_details->name();
[email protected]0d84c5d2009-10-09 01:10:421507
[email protected]a27a9382009-02-11 23:55:101508 if (child_process_stats_buffer_.find(child_name) ==
1509 child_process_stats_buffer_.end()) {
[email protected]0d84c5d2009-10-09 01:10:421510 child_process_stats_buffer_[child_name] =
1511 ChildProcessStats(child_details->type());
initial.commit09911bf2008-07-26 23:55:291512 }
1513
[email protected]a27a9382009-02-11 23:55:101514 ChildProcessStats& stats = child_process_stats_buffer_[child_name];
[email protected]432115822011-07-10 15:52:271515 switch (type) {
1516 case content::NOTIFICATION_CHILD_PROCESS_HOST_CONNECTED:
initial.commit09911bf2008-07-26 23:55:291517 stats.process_launches++;
1518 break;
1519
[email protected]432115822011-07-10 15:52:271520 case content::NOTIFICATION_CHILD_INSTANCE_CREATED:
initial.commit09911bf2008-07-26 23:55:291521 stats.instances++;
1522 break;
1523
[email protected]432115822011-07-10 15:52:271524 case content::NOTIFICATION_CHILD_PROCESS_CRASHED:
initial.commit09911bf2008-07-26 23:55:291525 stats.process_crashes++;
[email protected]1f085622009-12-04 05:33:451526 // Exclude plugin crashes from the count below because we report them via
1527 // a separate UMA metric.
1528 if (child_details->type() != ChildProcessInfo::PLUGIN_PROCESS) {
1529 IncrementPrefValue(prefs::kStabilityChildProcessCrashCount);
1530 }
initial.commit09911bf2008-07-26 23:55:291531 break;
1532
1533 default:
[email protected]432115822011-07-10 15:52:271534 NOTREACHED() << "Unexpected notification type " << type;
initial.commit09911bf2008-07-26 23:55:291535 return;
1536 }
1537}
1538
1539// Recursively counts the number of bookmarks and folders in node.
[email protected]b3c33d462009-06-26 22:29:201540static void CountBookmarks(const BookmarkNode* node,
1541 int* bookmarks,
1542 int* folders) {
[email protected]0890e60e2011-06-27 14:55:211543 if (node->is_url())
initial.commit09911bf2008-07-26 23:55:291544 (*bookmarks)++;
1545 else
1546 (*folders)++;
[email protected]9c1a75a2011-03-10 02:38:121547 for (int i = 0; i < node->child_count(); ++i)
initial.commit09911bf2008-07-26 23:55:291548 CountBookmarks(node->GetChild(i), bookmarks, folders);
1549}
1550
[email protected]b3c33d462009-06-26 22:29:201551void MetricsService::LogBookmarks(const BookmarkNode* node,
[email protected]57ecc4b2010-08-11 03:02:511552 const char* num_bookmarks_key,
1553 const char* num_folders_key) {
initial.commit09911bf2008-07-26 23:55:291554 DCHECK(node);
1555 int num_bookmarks = 0;
1556 int num_folders = 0;
1557 CountBookmarks(node, &num_bookmarks, &num_folders);
1558 num_folders--; // Don't include the root folder in the count.
1559
1560 PrefService* pref = g_browser_process->local_state();
1561 DCHECK(pref);
1562 pref->SetInteger(num_bookmarks_key, num_bookmarks);
1563 pref->SetInteger(num_folders_key, num_folders);
1564}
1565
[email protected]d8e41ed2008-09-11 15:22:321566void MetricsService::LogBookmarks(BookmarkModel* model) {
initial.commit09911bf2008-07-26 23:55:291567 DCHECK(model);
[email protected]72bdcfe2011-07-22 17:21:581568 LogBookmarks(model->bookmark_bar_node(),
initial.commit09911bf2008-07-26 23:55:291569 prefs::kNumBookmarksOnBookmarkBar,
1570 prefs::kNumFoldersOnBookmarkBar);
1571 LogBookmarks(model->other_node(),
1572 prefs::kNumBookmarksInOtherBookmarkFolder,
1573 prefs::kNumFoldersInOtherBookmarkFolder);
1574 ScheduleNextStateSave();
1575}
1576
[email protected]8e5c89a2011-06-07 18:13:331577void MetricsService::LogKeywords(const TemplateURLService* url_model) {
initial.commit09911bf2008-07-26 23:55:291578 DCHECK(url_model);
1579
1580 PrefService* pref = g_browser_process->local_state();
1581 DCHECK(pref);
1582 pref->SetInteger(prefs::kNumKeywords,
1583 static_cast<int>(url_model->GetTemplateURLs().size()));
1584 ScheduleNextStateSave();
1585}
1586
1587void MetricsService::RecordPluginChanges(PrefService* pref) {
[email protected]f8628c22011-04-05 12:10:181588 ListPrefUpdate update(pref, prefs::kStabilityPluginStats);
1589 ListValue* plugins = update.Get();
initial.commit09911bf2008-07-26 23:55:291590 DCHECK(plugins);
1591
1592 for (ListValue::iterator value_iter = plugins->begin();
1593 value_iter != plugins->end(); ++value_iter) {
1594 if (!(*value_iter)->IsType(Value::TYPE_DICTIONARY)) {
[email protected]a063c102010-07-22 22:20:191595 NOTREACHED();
initial.commit09911bf2008-07-26 23:55:291596 continue;
1597 }
1598
1599 DictionaryValue* plugin_dict = static_cast<DictionaryValue*>(*value_iter);
[email protected]57ecc4b2010-08-11 03:02:511600 std::string plugin_name;
[email protected]8e50b602009-03-03 22:59:431601 plugin_dict->GetString(prefs::kStabilityPluginName, &plugin_name);
[email protected]6470ee8f2009-03-03 20:46:401602 if (plugin_name.empty()) {
[email protected]a063c102010-07-22 22:20:191603 NOTREACHED();
initial.commit09911bf2008-07-26 23:55:291604 continue;
1605 }
1606
[email protected]57ecc4b2010-08-11 03:02:511607 // TODO(viettrungluu): remove conversions
[email protected]68b9e72b2011-08-05 23:08:221608 string16 name16 = UTF8ToUTF16(plugin_name);
1609 if (child_process_stats_buffer_.find(name16) ==
1610 child_process_stats_buffer_.end()) {
initial.commit09911bf2008-07-26 23:55:291611 continue;
[email protected]68b9e72b2011-08-05 23:08:221612 }
initial.commit09911bf2008-07-26 23:55:291613
[email protected]68b9e72b2011-08-05 23:08:221614 ChildProcessStats stats = child_process_stats_buffer_[name16];
initial.commit09911bf2008-07-26 23:55:291615 if (stats.process_launches) {
1616 int launches = 0;
[email protected]8e50b602009-03-03 22:59:431617 plugin_dict->GetInteger(prefs::kStabilityPluginLaunches, &launches);
initial.commit09911bf2008-07-26 23:55:291618 launches += stats.process_launches;
[email protected]8e50b602009-03-03 22:59:431619 plugin_dict->SetInteger(prefs::kStabilityPluginLaunches, launches);
initial.commit09911bf2008-07-26 23:55:291620 }
1621 if (stats.process_crashes) {
1622 int crashes = 0;
[email protected]8e50b602009-03-03 22:59:431623 plugin_dict->GetInteger(prefs::kStabilityPluginCrashes, &crashes);
initial.commit09911bf2008-07-26 23:55:291624 crashes += stats.process_crashes;
[email protected]8e50b602009-03-03 22:59:431625 plugin_dict->SetInteger(prefs::kStabilityPluginCrashes, crashes);
initial.commit09911bf2008-07-26 23:55:291626 }
1627 if (stats.instances) {
1628 int instances = 0;
[email protected]8e50b602009-03-03 22:59:431629 plugin_dict->GetInteger(prefs::kStabilityPluginInstances, &instances);
initial.commit09911bf2008-07-26 23:55:291630 instances += stats.instances;
[email protected]8e50b602009-03-03 22:59:431631 plugin_dict->SetInteger(prefs::kStabilityPluginInstances, instances);
initial.commit09911bf2008-07-26 23:55:291632 }
1633
[email protected]68b9e72b2011-08-05 23:08:221634 child_process_stats_buffer_.erase(name16);
initial.commit09911bf2008-07-26 23:55:291635 }
1636
1637 // Now go through and add dictionaries for plugins that didn't already have
1638 // reports in Local State.
[email protected]68b9e72b2011-08-05 23:08:221639 for (std::map<string16, ChildProcessStats>::iterator cache_iter =
[email protected]a27a9382009-02-11 23:55:101640 child_process_stats_buffer_.begin();
1641 cache_iter != child_process_stats_buffer_.end(); ++cache_iter) {
[email protected]a27a9382009-02-11 23:55:101642 ChildProcessStats stats = cache_iter->second;
[email protected]0d84c5d2009-10-09 01:10:421643
1644 // Insert only plugins information into the plugins list.
1645 if (ChildProcessInfo::PLUGIN_PROCESS != stats.process_type)
1646 continue;
1647
[email protected]57ecc4b2010-08-11 03:02:511648 // TODO(viettrungluu): remove conversion
[email protected]68b9e72b2011-08-05 23:08:221649 std::string plugin_name = UTF16ToUTF8(cache_iter->first);
[email protected]0d84c5d2009-10-09 01:10:421650
initial.commit09911bf2008-07-26 23:55:291651 DictionaryValue* plugin_dict = new DictionaryValue;
1652
[email protected]8e50b602009-03-03 22:59:431653 plugin_dict->SetString(prefs::kStabilityPluginName, plugin_name);
1654 plugin_dict->SetInteger(prefs::kStabilityPluginLaunches,
initial.commit09911bf2008-07-26 23:55:291655 stats.process_launches);
[email protected]8e50b602009-03-03 22:59:431656 plugin_dict->SetInteger(prefs::kStabilityPluginCrashes,
initial.commit09911bf2008-07-26 23:55:291657 stats.process_crashes);
[email protected]8e50b602009-03-03 22:59:431658 plugin_dict->SetInteger(prefs::kStabilityPluginInstances,
initial.commit09911bf2008-07-26 23:55:291659 stats.instances);
1660 plugins->Append(plugin_dict);
1661 }
[email protected]a27a9382009-02-11 23:55:101662 child_process_stats_buffer_.clear();
initial.commit09911bf2008-07-26 23:55:291663}
1664
[email protected]432115822011-07-10 15:52:271665bool MetricsService::CanLogNotification(int type,
initial.commit09911bf2008-07-26 23:55:291666 const NotificationSource& source,
1667 const NotificationDetails& details) {
[email protected]2c910b72011-03-08 21:16:321668 // We simply don't log anything to UMA if there is a single incognito
initial.commit09911bf2008-07-26 23:55:291669 // session visible. The problem is that we always notify using the orginal
1670 // profile in order to simplify notification processing.
1671 return !BrowserList::IsOffTheRecordSessionActive();
1672}
1673
[email protected]57ecc4b2010-08-11 03:02:511674void MetricsService::RecordBooleanPrefValue(const char* path, bool value) {
initial.commit09911bf2008-07-26 23:55:291675 DCHECK(IsSingleThreaded());
1676
1677 PrefService* pref = g_browser_process->local_state();
1678 DCHECK(pref);
1679
1680 pref->SetBoolean(path, value);
1681 RecordCurrentState(pref);
1682}
1683
1684void MetricsService::RecordCurrentState(PrefService* pref) {
[email protected]0bb1a622009-03-04 03:22:321685 pref->SetInt64(prefs::kStabilityLastTimestampSec, Time::Now().ToTimeT());
initial.commit09911bf2008-07-26 23:55:291686
1687 RecordPluginChanges(pref);
1688}
1689
initial.commit09911bf2008-07-26 23:55:291690static bool IsSingleThreaded() {
[email protected]ce072a72010-12-31 20:02:161691 static base::PlatformThreadId thread_id = 0;
initial.commit09911bf2008-07-26 23:55:291692 if (!thread_id)
[email protected]ce072a72010-12-31 20:02:161693 thread_id = base::PlatformThread::CurrentId();
1694 return base::PlatformThread::CurrentId() == thread_id;
initial.commit09911bf2008-07-26 23:55:291695}
[email protected]5ccaa412009-11-13 22:00:161696
1697#if defined(OS_CHROMEOS)
[email protected]29cf16772010-04-21 15:13:471698void MetricsService::StartExternalMetrics() {
[email protected]5ccaa412009-11-13 22:00:161699 external_metrics_ = new chromeos::ExternalMetrics;
[email protected]29cf16772010-04-21 15:13:471700 external_metrics_->Start();
[email protected]5ccaa412009-11-13 22:00:161701}
1702#endif