summaryrefslogtreecommitdiffstats
path: root/chrome/browser/metrics/metrics_service.h
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/metrics/metrics_service.h')
-rw-r--r--chrome/browser/metrics/metrics_service.h464
1 files changed, 464 insertions, 0 deletions
diff --git a/chrome/browser/metrics/metrics_service.h b/chrome/browser/metrics/metrics_service.h
new file mode 100644
index 0000000..f0f69ed
--- /dev/null
+++ b/chrome/browser/metrics/metrics_service.h
@@ -0,0 +1,464 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file defines a service that collects information about the user
+// experience in order to help improve future versions of the app.
+
+#ifndef CHROME_BROWSER_METRICS_SERVICE_H__
+#define CHROME_BROWSER_METRICS_SERVICE_H__
+
+#include <list>
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/file_path.h"
+#include "base/histogram.h"
+#include "base/scoped_ptr.h"
+#include "base/values.h"
+#include "chrome/browser/metrics/metrics_log.h"
+#include "chrome/browser/url_fetcher.h"
+#include "chrome/common/notification_service.h"
+#include "webkit/glue/webplugin.h"
+
+class BookmarkModel;
+class BookmarkNode;
+class PrefService;
+class Profile;
+class TemplateURLModel;
+
+// This is used to quickly log stats from plugin-related notifications in
+// MetricsService::plugin_stats_buffer_. The buffer's contents are transferred
+// out when Local State is periodically saved. The information is then
+// reported to the UMA server on next launch.
+struct PluginStats {
+ public:
+ PluginStats() : process_launches(0), process_crashes(0), instances(0) {}
+
+ // The number of times that the given plugin process has been launched
+ int process_launches;
+
+ // The number of times that the given plugin process has crashed
+ int process_crashes;
+
+ // The number of instances of this plugin that have been created.
+ // An instance is a DOM object rendered by this plugin during a page load.
+ int instances;
+};
+
+class MetricsService : public NotificationObserver,
+ public URLFetcher::Delegate {
+ public:
+ MetricsService();
+ virtual ~MetricsService();
+
+ // Sets whether the user permits uploading. The argument of this function
+ // should match the checkbox in Options.
+ void SetUserPermitsUpload(bool enabled);
+
+ // Start/stop the metrics recording and uploading machine. These should be
+ // used on startup and when the user clicks the checkbox in the prefs.
+ // StartRecordingOnly starts the metrics recording but not reporting, for use
+ // in tests only.
+ void Start();
+ void StartRecordingOnly();
+ void Stop();
+
+ // At startup, prefs needs to be called with a list of all the pref names and
+ // types we'll be using.
+ static void RegisterPrefs(PrefService* local_state);
+
+ // Implementation of NotificationObserver
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ // This should be called when the application is shutting down, to record
+ // the fact that this was a clean shutdown in the stability metrics.
+ void RecordCleanShutdown();
+
+ // Invoked when we get a WM_SESSIONEND. This places a value in prefs that is
+ // reset when RecordCompletedSessionEnd is invoked.
+ void RecordStartOfSessionEnd();
+
+ // This should be called when the application is shutting down. It records
+ // that session end was successful.
+ void RecordCompletedSessionEnd();
+
+ // Saves in the preferences if the crash report registration was successful.
+ // This count is eventually send via UMA logs.
+ void RecordBreakpadRegistration(bool success);
+
+ // Saves in the preferences if the browser is running under a debugger.
+ // This count is eventually send via UMA logs.
+ void RecordBreakpadHasDebugger(bool has_debugger);
+
+ // Callback to let us knew that the plugin list is warmed up.
+ void OnGetPluginListTaskComplete();
+
+ // Save any unsent logs into a persistent store in a pref. We always do this
+ // at shutdown, but we can do it as we reduce the list as well.
+ void StoreUnsentLogs();
+
+ private:
+ // The MetricsService has a lifecycle that is stored as a state.
+ // See metrics_service.cc for description of this lifecycle.
+ enum State {
+ INITIALIZED, // Constructor was called.
+ PLUGIN_LIST_REQUESTED, // Waiting for plugin list to be loaded.
+ PLUGIN_LIST_ARRIVED, // Waiting for timer to send initial log.
+ INITIAL_LOG_READY, // Initial log generated, and waiting for reply.
+ SEND_OLD_INITIAL_LOGS, // Sending unsent logs from previous session.
+ SENDING_OLD_LOGS, // Sending unsent logs from previous session.
+ SENDING_CURRENT_LOGS, // Sending standard current logs as they acrue.
+ };
+
+ // Maintain a map of histogram names to the sample stats we've sent.
+ typedef std::map<std::string, Histogram::SampleSet> LoggedSampleMap;
+
+ class GetPluginListTask;
+ class GetPluginListTaskComplete;
+
+ // Sets and gets whether metrics recording is active.
+ // SetRecording(false) also forces a persistent save of logging state (if
+ // anything has been recorded, or transmitted).
+ void SetRecording(bool enabled);
+ bool recording_active() const;
+
+ // Enable/disable transmission of accumulated logs and crash reports (dumps).
+ // Return value "true" indicates setting was definitively set as requested).
+ // Return value of "false" indicates that the enable state is effectively
+ // stuck in the other logical setting.
+ // Google Update maintains the authoritative preference in the registry, so
+ // the caller *might* not be able to actually change the setting.
+ // It is always possible to set this to at least one value, which matches the
+ // current value reported by querying Google Update.
+ void SetReporting(bool enabled);
+ bool reporting_active() const;
+
+ // If in_idle is true, sets idle_since_last_transmission to true.
+ // If in_idle is false and idle_since_last_transmission_ is true, sets
+ // idle_since_last_transmission to false and starts the timer (provided
+ // starting the timer is permitted).
+ void HandleIdleSinceLastTransmission(bool in_idle);
+
+ // Set up client ID, session ID, etc.
+ void InitializeMetricsState();
+
+ // Generates a new client ID to use to identify self to metrics server.
+ static std::string GenerateClientID();
+
+ // Schedule the next save of LocalState information. This is called
+ // automatically by the task that performs each save to schedule the next one.
+ void ScheduleNextStateSave();
+
+ // Save the LocalState information immediately. This should not be called by
+ // anybody other than the scheduler to avoid doing too many writes. When you
+ // make a change, call ScheduleNextStateSave() instead.
+ void SaveLocalState();
+
+ // Called to start recording user experience metrics.
+ // Constructs a new, empty current_log_.
+ void StartRecording();
+
+ // Called to stop recording user experience metrics. The caller takes
+ // ownership of the resulting MetricsLog object via the log parameter,
+ // or passes in NULL to indicate that the log should simply be deleted.
+ void StopRecording(MetricsLog** log);
+
+ void ListenerRegistration(bool start_listening);
+
+ // Adds or Removes (depending on the value of is_add) the given observer
+ // to the given notification type for all sources.
+ static void AddOrRemoveObserver(NotificationObserver* observer,
+ NotificationType type,
+ bool is_add);
+
+ // Deletes pending_log_ and current_log_, and pushes their text into the
+ // appropriate unsent_log vectors. Called when Chrome shuts down.
+ void PushPendingLogsToUnsentLists();
+
+ // Save the pending_log_text_ persistently in a pref for transmission when we
+ // next run. Note that IF this text is "too large," we just dicard it.
+ void PushPendingLogTextToUnsentOngoingLogs();
+
+ // Start timer for next log transmission.
+ void StartLogTransmissionTimer();
+ // Do not call TryToStartTransmission() directly.
+ // Use StartLogTransmissionTimer() to schedule a call.
+ void TryToStartTransmission();
+
+ // Takes whatever log should be uploaded next (according to the state_)
+ // and makes it the pending log. If pending_log_ is not NULL,
+ // MakePendingLog does nothing and returns.
+ void MakePendingLog();
+
+ // Determines from state_ and permissions set out by the server and by
+ // the user whether the pending_log_ should be sent or discarded. Called by
+ // TryToStartTransmission.
+ bool TransmissionPermitted() const;
+
+ // Internal function to collect process memory information.
+ void CollectMemoryDetails();
+
+ // Check to see if there is a log that needs to be, or is being, transmitted.
+ bool pending_log() const {
+ return pending_log_ || !pending_log_text_.empty();
+ }
+ // Check to see if there are any unsent logs from previous sessions.
+ bool unsent_logs() const {
+ return !unsent_initial_logs_.empty() || !unsent_ongoing_logs_.empty();
+ }
+ // Record stats, client ID, Session ID, etc. in a special "first" log.
+ void PrepareInitialLog();
+ // Pull copies of unsent logs from prefs into instance variables.
+ void RecallUnsentLogs();
+ // Convert pending_log_ to XML in pending_log_text_ for transmission.
+ void PreparePendingLogText();
+
+ // Convert pending_log_ to XML, compress it, and prepare to pass to server.
+ // Upon return, current_fetch_ should be reset with its upload data set to
+ // a compressed copy of the pending log.
+ void PrepareFetchWithPendingLog();
+
+ // Discard pending_log_, and clear pending_log_text_. Called after processing
+ // of this log is complete.
+ void DiscardPendingLog();
+ // Compress the report log in input using bzip2, store the result in output.
+ bool Bzip2Compress(const std::string& input, std::string* output);
+ // Implementation of URLFetcher::Delegate. Called after transmission
+ // completes (either successfully or with failure).
+ virtual void OnURLFetchComplete(const URLFetcher* source,
+ const GURL& url,
+ const URLRequestStatus& status,
+ int response_code,
+ const ResponseCookies& cookies,
+ const std::string& data);
+
+ // Called by OnURLFetchComplete to handle the case when the server returned
+ // a response code not equal to 200.
+ void HandleBadResponseCode();
+
+ // Class to hold all attributes that gets inherited by children in the UMA
+ // response data xml tree. This is to make it convenient in the
+ // recursive function that does the tree traversal to pass all such
+ // data in the recursive call. If you want to add more such attributes,
+ // add them to this class.
+ class InheritedProperties {
+ public:
+ InheritedProperties() : salt(123123), denominator(1000000) {}
+ int salt, denominator;
+ // Notice salt and denominator are inherited from parent nodes, but
+ // not probability; the default value of probability is 1.
+
+ // When a new node is reached it might have fields which overwrite inherited
+ // properties for that node (and its children). Call this method to
+ // overwrite those settings.
+ void OverwriteWhereNeeded(xmlNodePtr node);
+ };
+
+ // Called by OnURLFetchComplete with data as the argument
+ // parses the xml returned by the server in the call to OnURLFetchComplete
+ // and extracts settings for subsequent frequency and content of log posts.
+ void GetSettingsFromResponseData(const std::string& data);
+
+ // This is a helper function for GetSettingsFromResponseData which iterates
+ // through the xml tree at the level of the <chrome_config> node.
+ void GetSettingsFromChromeConfigNode(xmlNodePtr chrome_config_node);
+
+ // GetSettingsFromUploadNode handles iteration over the children of the
+ // <upload> child of the <chrome_config> node. It calls the recursive
+ // function GetSettingsFromUploadNodeRecursive which does the actual
+ // tree traversal.
+ void GetSettingsFromUploadNode(xmlNodePtr upload_node);
+ void GetSettingsFromUploadNodeRecursive(xmlNodePtr node,
+ InheritedProperties props,
+ std::string path_prefix,
+ bool uploadOn);
+
+ // NodeProbabilityTest gets called at every node in the tree traversal
+ // performed by GetSettingsFromUploadNodeRecursive. It determines from
+ // the inherited attributes (salt, denominator) and the probability
+ // assiciated with the node whether that node and its contents should
+ // contribute to the upload.
+ bool NodeProbabilityTest(xmlNodePtr node, InheritedProperties props) const;
+ bool ProbabilityTest(double probability, int salt, int denominator) const;
+
+ // Records a window-related notification.
+ void LogWindowChange(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ // Reads, increments and then sets the specified integer preference.
+ void IncrementPrefValue(const wchar_t* path);
+
+ // Records a renderer process crash.
+ void LogRendererCrash();
+
+ // Records a renderer process hang.
+ void LogRendererHang();
+
+ // Records the desktop security status of a renderer in the sandbox at
+ // creation time.
+ void LogRendererInSandbox(bool on_sandbox_desktop);
+
+ // Set the value in preferences for for the number of bookmarks and folders
+ // in node. The pref key for the number of bookmarks in num_bookmarks_key and
+ // the pref key for number of folders in num_folders_key.
+ void LogBookmarks(BookmarkNode* node,
+ const wchar_t* num_bookmarks_key,
+ const wchar_t* num_folders_key);
+
+ // Sets preferences for the for the number of bookmarks in model.
+ void LogBookmarks(BookmarkModel* model);
+
+ // Records a plugin-related notification. These are recorded to an in-object
+ // buffer because these notifications are sent on page load, and we don't
+ // want to slow that down.
+ void LogPluginChange(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ // Logs keywords specific metrics. Keyword metrics are recorded in the
+ // profile specific metrics.
+ void LogKeywords(const TemplateURLModel* url_model);
+
+ // Saves plugin-related updates from the in-object buffer to Local State
+ // for retrieval next time we send a Profile log (generally next launch).
+ void RecordPluginChanges(PrefService* pref);
+
+ // Records state that should be periodically saved, like uptime and
+ // buffered plugin stability statistics.
+ void RecordCurrentState(PrefService* pref);
+
+ // Record complete list of histograms into the current log.
+ // Called when we close a log.
+ void RecordCurrentHistograms();
+ // Record a specific histogram .
+ void RecordHistogram(const Histogram& histogram);
+
+ // Logs the initiation of a page load
+ void LogLoadStarted();
+
+ // Records a page load notification.
+ void LogLoadComplete(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ // Adds a profile metric with the specified key/value pair.
+ void AddProfileMetric(Profile* profile, const std::wstring& key,
+ int value);
+
+ // Checks whether a notification can be logged.
+ bool CanLogNotification(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ // Sets the value of the specified path in prefs and schedules a save.
+ void RecordBooleanPrefValue(const wchar_t* path, bool value);
+
+ // Indicate whether recording and reporting are currently happening.
+ // These should not be set directly, but by calling SetRecording and
+ // SetReporting.
+ bool recording_active_;
+ bool reporting_active_;
+
+ // Coincides with the check box in options window that lets the user control
+ // whether to upload.
+ bool user_permits_upload_;
+
+ // The variable server_permits_upload_ is set true when the response
+ // data forbids uploading. This should coinside with the "die roll"
+ // with probability in the upload tag of the response data came out
+ // affirmative.
+ bool server_permits_upload_;
+
+ // The progession of states made by the browser are recorded in the following
+ // state.
+ State state_;
+
+ // A log that we are currently transmiting, or about to try to transmit.
+ MetricsLog* pending_log_;
+
+ // An alternate form of pending_log_. We persistently save this text version
+ // into prefs if we can't transmit it. As a result, sometimes all we have is
+ // the text version (recalled from a previous session).
+ std::string pending_log_text_;
+
+ // The outstanding transmission appears as a URL Fetch operation.
+ scoped_ptr<URLFetcher> current_fetch_;
+
+ // The log that we are still appending to.
+ MetricsLog* current_log_;
+
+ // The identifier that's sent to the server with the log reports.
+ std::string client_id_;
+
+ // Whether the MetricsService object has received any notifications since
+ // the last time a transmission was sent.
+ bool idle_since_last_transmission_;
+
+ // A number that identifies the how many times the app has been launched.
+ int session_id_;
+
+ // When logs were not sent during a previous session they are queued to be
+ // sent instead of currently accumulating logs. We give preference to sending
+ // our inital log first, then unsent intial logs, then unsent ongoing logs.
+ // Unsent logs are gathered at shutdown, and save in a persistent pref, one
+ // log in each string in the following arrays.
+ // Note that the vector has the oldest logs listed first (early in the
+ // vector), and we'll discard old logs if we have gathered too many logs.
+ std::vector<std::string> unsent_initial_logs_;
+ std::vector<std::string> unsent_ongoing_logs_;
+
+ // Maps NavigationControllers (corresponding to tabs) or Browser
+ // (corresponding to Windows) to a unique integer that we will use to identify
+ // it. |next_window_id_| is used to track which IDs we have used so far.
+ typedef std::map<uintptr_t, int> WindowMap;
+ WindowMap window_map_;
+ int next_window_id_;
+
+ // Buffer of plugin notifications for quick access. See PluginStats
+ // documentation above for more details.
+ std::map<FilePath, PluginStats> plugin_stats_buffer_;
+
+ ScopedRunnableMethodFactory<MetricsService> log_sender_factory_;
+ ScopedRunnableMethodFactory<MetricsService> state_saver_factory_;
+
+ // Dictionary containing all the profile specific metrics. This is set
+ // at creation time from the prefs.
+ scoped_ptr<DictionaryValue> profile_dictionary_;
+
+ // For histograms, record what we've already logged (as a sample for each
+ // histogram) so that we can send only the delta with the next log.
+ MetricsService::LoggedSampleMap logged_samples_;
+
+ // The interval between consecutive log transmissions (to avoid hogging the
+ // outbound network link). This is usually also the duration for which we
+ // build up a log, but if other unsent-logs from previous sessions exist, we
+ // quickly transmit those unsent logs while we continue to build a log.
+ base::TimeDelta interlog_duration_;
+
+ // The maximum number of events which get transmitted in a log. This defaults
+ // to a constant and otherwise is provided by the UMA server in the server
+ // response data.
+ int log_event_limit_;
+
+ // The types of data that are to be included in the logs and histograms
+ // according to the UMA response data.
+ std::set<std::string> logs_to_upload_;
+ std::set<std::string> logs_to_omit_;
+ std::set<std::string> histograms_to_upload_;
+ std::set<std::string> histograms_to_omit_;
+
+ // Indicate that a timer for sending the next log has already been queued.
+ bool timer_pending_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(MetricsService);
+};
+
+#endif // CHROME_BROWSER_METRICS_SERVICE_H__
+