diff options
Diffstat (limited to 'components/metrics/metrics_service.h')
-rw-r--r-- | components/metrics/metrics_service.h | 468 |
1 files changed, 468 insertions, 0 deletions
diff --git a/components/metrics/metrics_service.h b/components/metrics/metrics_service.h new file mode 100644 index 0000000..b586263 --- /dev/null +++ b/components/metrics/metrics_service.h @@ -0,0 +1,468 @@ +// Copyright 2014 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 COMPONENTS_METRICS_METRICS_SERVICE_H_ +#define COMPONENTS_METRICS_METRICS_SERVICE_H_ + +#include <map> +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/gtest_prod_util.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/scoped_vector.h" +#include "base/memory/weak_ptr.h" +#include "base/metrics/field_trial.h" +#include "base/metrics/histogram_flattener.h" +#include "base/metrics/histogram_snapshot_manager.h" +#include "base/metrics/user_metrics.h" +#include "base/observer_list.h" +#include "base/strings/string16.h" +#include "base/threading/thread_checker.h" +#include "base/time/time.h" +#include "components/metrics/metrics_log.h" +#include "components/metrics/metrics_log_manager.h" +#include "components/metrics/metrics_provider.h" +#include "components/metrics/metrics_service_observer.h" +#include "components/variations/active_field_trials.h" + +class MetricsReportingScheduler; +class PrefService; +class PrefRegistrySimple; + +namespace base { +class DictionaryValue; +class HistogramSamples; +class MessageLoopProxy; +class PrefService; +} + +namespace variations { +struct ActiveGroupId; +} + +namespace metrics { +class MetricsLogUploader; +class MetricsServiceClient; +class MetricsStateManager; +} + +namespace net { +class URLFetcher; +} + +// A Field Trial and its selected group, which represent a particular +// Chrome configuration state. For example, the trial name could map to +// a preference name, and the group name could map to a preference value. +struct SyntheticTrialGroup { + public: + ~SyntheticTrialGroup(); + + variations::ActiveGroupId id; + base::TimeTicks start_time; + + private: + friend class MetricsService; + FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest, RegisterSyntheticTrial); + + // This constructor is private specifically so as to control which code is + // able to access it. New code that wishes to use it should be added as a + // friend class. + SyntheticTrialGroup(uint32 trial, uint32 group); +}; + +class MetricsService : public base::HistogramFlattener { + public: + // The execution phase of the browser. + enum ExecutionPhase { + UNINITIALIZED_PHASE = 0, + START_METRICS_RECORDING = 100, + CREATE_PROFILE = 200, + STARTUP_TIMEBOMB_ARM = 300, + THREAD_WATCHER_START = 400, + MAIN_MESSAGE_LOOP_RUN = 500, + SHUTDOWN_TIMEBOMB_ARM = 600, + SHUTDOWN_COMPLETE = 700, + }; + + // Creates the MetricsService with the given |state_manager|, |client|, and + // |local_state|. Does not take ownership of the paramaters; instead stores + // a weak pointer to each. Caller should ensure that the parameters are valid + // for the lifetime of this class. + MetricsService(metrics::MetricsStateManager* state_manager, + metrics::MetricsServiceClient* client, + PrefService* local_state); + virtual ~MetricsService(); + + // Initializes metrics recording state. Updates various bookkeeping values in + // prefs and sets up the scheduler. This is a separate function rather than + // being done by the constructor so that field trials could be created before + // this is run. + void InitializeMetricsRecordingState(); + + // Starts the metrics system, turning on recording and uploading of metrics. + // Should be called when starting up with metrics enabled, or when metrics + // are turned on. + void Start(); + + // If metrics reporting is enabled, starts the metrics service. Returns + // whether the metrics service was started. + bool StartIfMetricsReportingEnabled(); + + // Starts the metrics system in a special test-only mode. Metrics won't ever + // be uploaded or persisted in this mode, but metrics will be recorded in + // memory. + void StartRecordingForTests(); + + // Shuts down the metrics system. Should be called at shutdown, or if metrics + // are turned off. + void Stop(); + + // Enable/disable transmission of accumulated logs and crash reports (dumps). + // Calling Start() automatically enables reporting, but sending is + // asyncronous so this can be called immediately after Start() to prevent + // any uploading. + void EnableReporting(); + void DisableReporting(); + + // Returns the client ID for this client, or the empty string if metrics + // recording is not currently running. + std::string GetClientId(); + + // Returns the preferred entropy provider used to seed persistent activities + // based on whether or not metrics reporting will be permitted on this client. + // + // If metrics reporting is enabled, this method returns an entropy provider + // that has a high source of entropy, partially based on the client ID. + // Otherwise, it returns an entropy provider that is based on a low entropy + // source. + scoped_ptr<const base::FieldTrial::EntropyProvider> CreateEntropyProvider(); + + // At startup, prefs needs to be called with a list of all the pref names and + // types we'll be using. + static void RegisterPrefs(PrefRegistrySimple* registry); + + // HistogramFlattener: + virtual void RecordDelta(const base::HistogramBase& histogram, + const base::HistogramSamples& snapshot) OVERRIDE; + virtual void InconsistencyDetected( + base::HistogramBase::Inconsistency problem) OVERRIDE; + virtual void UniqueInconsistencyDetected( + base::HistogramBase::Inconsistency problem) OVERRIDE; + virtual void InconsistencyDetectedInLoggedCount(int amount) OVERRIDE; + + // This should be called when the application is not idle, i.e. the user seems + // to be interacting with the application. + void OnApplicationNotIdle(); + + // 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(); + +#if defined(OS_ANDROID) || defined(OS_IOS) + // Called when the application is going into background mode. + void OnAppEnterBackground(); + + // Called when the application is coming out of background mode. + void OnAppEnterForeground(); +#else + // Set the dirty flag, which will require a later call to LogCleanShutdown(). + static void LogNeedForCleanShutdown(PrefService* local_state); +#endif // defined(OS_ANDROID) || defined(OS_IOS) + + static void SetExecutionPhase(ExecutionPhase execution_phase, + PrefService* local_state); + + // 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); + + bool recording_active() const; + bool reporting_active() const; + + // Redundant test to ensure that we are notified of a clean exit. + // This value should be true when process has completed shutdown. + static bool UmaMetricsProperlyShutdown(); + + // Registers a field trial name and group to be used to annotate a UMA report + // with a particular Chrome configuration state. A UMA report will be + // annotated with this trial group if and only if all events in the report + // were created after the trial is registered. Only one group name may be + // registered at a time for a given trial_name. Only the last group name that + // is registered for a given trial name will be recorded. The values passed + // in must not correspond to any real field trial in the code. + // To use this method, SyntheticTrialGroup should friend your class. + void RegisterSyntheticFieldTrial(const SyntheticTrialGroup& trial_group); + + // Register the specified |provider| to provide additional metrics into the + // UMA log. Should be called during MetricsService initialization only. + void RegisterMetricsProvider(scoped_ptr<metrics::MetricsProvider> provider); + + // Check if this install was cloned or imaged from another machine. If a + // clone is detected, reset the client id and low entropy source. This + // should not be called more than once. + void CheckForClonedInstall( + scoped_refptr<base::SingleThreadTaskRunner> task_runner); + + protected: + // Exposed for testing. + metrics::MetricsLogManager* log_manager() { return &log_manager_; } + + 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. + INIT_TASK_SCHEDULED, // Waiting for deferred init tasks to + // complete. + INIT_TASK_DONE, // Waiting for timer to send initial log. + SENDING_INITIAL_STABILITY_LOG, // Initial stability log being sent. + SENDING_INITIAL_METRICS_LOG, // Initial metrics log being sent. + SENDING_OLD_LOGS, // Sending unsent logs from last session. + SENDING_CURRENT_LOGS, // Sending ongoing logs as they accrue. + }; + + enum ShutdownCleanliness { + CLEANLY_SHUTDOWN = 0xdeadbeef, + NEED_TO_SHUTDOWN = ~CLEANLY_SHUTDOWN + }; + + typedef std::vector<SyntheticTrialGroup> SyntheticTrialGroups; + + // Calls into the client to start metrics gathering. + void StartGatheringMetrics(); + + // Callback that moves the state to INIT_TASK_DONE. When this is called, the + // state should be INIT_TASK_SCHEDULED. + void FinishedGatheringInitialMetrics(); + + void OnUserAction(const std::string& action); + + // Get the amount of uptime since this process started and since the last + // call to this function. Also updates the cumulative uptime metric (stored + // as a pref) for uninstall. Uptimes are measured using TimeTicks, which + // guarantees that it is monotonic and does not jump if the user changes + // his/her clock. The TimeTicks implementation also makes the clock not + // count time the computer is suspended. + void GetUptimes(PrefService* pref, + base::TimeDelta* incremental_uptime, + base::TimeDelta* uptime); + + // Turns recording on or off. + // DisableRecording() also forces a persistent save of logging state (if + // anything has been recorded, or transmitted). + void EnableRecording(); + void DisableRecording(); + + // 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(); + + // Registers/unregisters |observer| to receive MetricsLog notifications. + void AddObserver(MetricsServiceObserver* observer); + void RemoveObserver(MetricsServiceObserver* observer); + void NotifyOnDidCreateMetricsLog(); + + // 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(); + + // Opens a new log for recording user experience metrics. + void OpenNewLog(); + + // Closes out the current log after adding any last information. + void CloseCurrentLog(); + + // Pushes the text of the current and staged logs into persistent storage. + // Called when Chrome shuts down. + void PushPendingLogsToPersistentStorage(); + + // Ensures that scheduler is running, assuming the current settings are such + // that metrics should be reported. If not, this is a no-op. + void StartSchedulerIfNecessary(); + + // Starts the process of uploading metrics data. + void StartScheduledUpload(); + + // Called by the client when final log info collection is complete. + void OnFinalLogInfoCollectionDone(); + + // Either closes the current log or creates and closes the initial log + // (depending on |state_|), and stages it for upload. + void StageNewLog(); + + // Prepares the initial stability log, which is only logged when the previous + // run of Chrome crashed. This log contains any stability metrics left over + // from that previous run, and only these stability metrics. It uses the + // system profile from the previous session. + void PrepareInitialStabilityLog(); + + // Prepares the initial metrics log, which includes startup histograms and + // profiler data, as well as incremental stability-related metrics. + void PrepareInitialMetricsLog(); + + // Uploads the currently staged log (which must be non-null). + void SendStagedLog(); + + // Called after transmission completes (either successfully or with failure). + void OnLogUploadComplete(int response_code); + + // Reads, increments and then sets the specified integer preference. + void IncrementPrefValue(const char* path); + + // Reads, increments and then sets the specified long preference that is + // stored as a string. + void IncrementLongPrefsValue(const char* path); + + // Records that the browser was shut down cleanly. + void LogCleanShutdown(); + + // Records state that should be periodically saved, like uptime and + // buffered plugin stability statistics. + void RecordCurrentState(PrefService* pref); + + // Checks whether events should currently be logged. + bool ShouldLogEvents(); + + // Sets the value of the specified path in prefs and schedules a save. + void RecordBooleanPrefValue(const char* path, bool value); + + // Returns a list of synthetic field trials that were active for the entire + // duration of the current log. + void GetCurrentSyntheticFieldTrials( + std::vector<variations::ActiveGroupId>* synthetic_trials); + + // Creates a new MetricsLog instance with the given |log_type|. + scoped_ptr<MetricsLog> CreateLog(MetricsLog::LogType log_type); + + // Record complete list of histograms into the current log. + // Called when we close a log. + void RecordCurrentHistograms(); + + // Record complete list of stability histograms into the current log, + // i.e., histograms with the |kUmaStabilityHistogramFlag| flag set. + void RecordCurrentStabilityHistograms(); + + // Manager for the various in-flight logs. + metrics::MetricsLogManager log_manager_; + + // |histogram_snapshot_manager_| prepares histogram deltas for transmission. + base::HistogramSnapshotManager histogram_snapshot_manager_; + + // Used to manage various metrics reporting state prefs, such as client id, + // low entropy source and whether metrics reporting is enabled. Weak pointer. + metrics::MetricsStateManager* const state_manager_; + + // Used to interact with the embedder. Weak pointer; must outlive |this| + // instance. + metrics::MetricsServiceClient* const client_; + + // Registered metrics providers. + ScopedVector<metrics::MetricsProvider> metrics_providers_; + + PrefService* local_state_; + + base::ActionCallback action_callback_; + + // 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_; + + // Indicate whether test mode is enabled, where the initial log should never + // be cut, and logs are neither persisted nor uploaded. + bool test_mode_active_; + + // The progression of states made by the browser are recorded in the following + // state. + State state_; + + // Whether the initial stability log has been recorded during startup. + bool has_initial_stability_log_; + + // The initial metrics log, used to record startup metrics (histograms and + // profiler data). Note that if a crash occurred in the previous session, an + // initial stability log may be sent before this. + scoped_ptr<MetricsLog> initial_metrics_log_; + + // Instance of the helper class for uploading logs. + scoped_ptr<metrics::MetricsLogUploader> log_uploader_; + + // Whether there is a current log upload in progress. + bool log_upload_in_progress_; + + // 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_; + + // Weak pointers factory used to post task on different threads. All weak + // pointers managed by this factory have the same lifetime as MetricsService. + base::WeakPtrFactory<MetricsService> self_ptr_factory_; + + // Weak pointers factory used for saving state. All weak pointers managed by + // this factory are invalidated in ScheduleNextStateSave. + base::WeakPtrFactory<MetricsService> state_saver_factory_; + + // The scheduler for determining when uploads should happen. + scoped_ptr<MetricsReportingScheduler> scheduler_; + + // Stores the time of the first call to |GetUptimes()|. + base::TimeTicks first_updated_time_; + + // Stores the time of the last call to |GetUptimes()|. + base::TimeTicks last_updated_time_; + + // Execution phase the browser is in. + static ExecutionPhase execution_phase_; + + // Reduntant marker to check that we completed our shutdown, and set the + // exited-cleanly bit in the prefs. + static ShutdownCleanliness clean_shutdown_status_; + + // Field trial groups that map to Chrome configuration states. + SyntheticTrialGroups synthetic_trial_groups_; + + ObserverList<MetricsServiceObserver> observers_; + + // Confirms single-threaded access to |observers_| in debug builds. + base::ThreadChecker thread_checker_; + + friend class MetricsServiceAccessor; + + FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest, IsPluginProcess); + FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest, MetricsServiceObserver); + FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest, + PermutedEntropyCacheClearedWhenLowEntropyReset); + FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest, RegisterSyntheticTrial); + + DISALLOW_COPY_AND_ASSIGN(MetricsService); +}; + +#endif // COMPONENTS_METRICS_METRICS_SERVICE_H_ |