Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 //------------------------------------------------------------------------------ | 5 //------------------------------------------------------------------------------ |
| 6 // Description of the life cycle of a instance of MetricsService. | 6 // Description of the life cycle of a instance of MetricsService. |
| 7 // | 7 // |
| 8 // OVERVIEW | 8 // OVERVIEW |
| 9 // | 9 // |
| 10 // A MetricsService instance is typically created at application startup. It | 10 // A MetricsService instance is typically created at application startup. It |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 82 // SENDING_OLD_LOGS, // Sending unsent logs from previous session. | 82 // SENDING_OLD_LOGS, // Sending unsent logs from previous session. |
| 83 // SENDING_CURRENT_LOGS, // Sending standard current logs as they accrue. | 83 // SENDING_CURRENT_LOGS, // Sending standard current logs as they accrue. |
| 84 // | 84 // |
| 85 // In more detail, we have: | 85 // In more detail, we have: |
| 86 // | 86 // |
| 87 // INITIALIZED, // Constructor was called. | 87 // INITIALIZED, // Constructor was called. |
| 88 // The MS has been constructed, but has taken no actions to compose the | 88 // The MS has been constructed, but has taken no actions to compose the |
| 89 // initial log. | 89 // initial log. |
| 90 // | 90 // |
| 91 // INIT_TASK_SCHEDULED, // Waiting for deferred init tasks to complete. | 91 // INIT_TASK_SCHEDULED, // Waiting for deferred init tasks to complete. |
| 92 // Typically about 30 seconds after startup, a task is sent to a second thread | 92 // Typically about 30 seconds after startup, a task is posted to perform |
| 93 // (the file thread) to perform deferred (lower priority and slower) | 93 // deferred (lower priority and slower) initialization steps such as getting the |
| 94 // initialization steps such as getting the list of plugins. That task will | 94 // list of plugins. That task will (when complete) make an async callback (via |
| 95 // (when complete) make an async callback (via a Task) to indicate the | 95 // a Task) to indicate the completion. |
| 96 // completion. | |
| 97 // | 96 // |
| 98 // INIT_TASK_DONE, // Waiting for timer to send initial log. | 97 // INIT_TASK_DONE, // Waiting for timer to send initial log. |
| 99 // The callback has arrived, and it is now possible for an initial log to be | 98 // The callback has arrived, and it is now possible for an initial log to be |
| 100 // created. This callback typically arrives back less than one second after | 99 // created. This callback typically arrives back less than one second after |
| 101 // the deferred init task is dispatched. | 100 // the deferred init task is dispatched. |
| 102 // | 101 // |
| 103 // INITIAL_LOG_READY, // Initial log generated, and waiting for reply. | 102 // INITIAL_LOG_READY, // Initial log generated, and waiting for reply. |
| 104 // This state is entered only after an initial log has been composed, and | 103 // This state is entered only after an initial log has been composed, and |
| 105 // prepared for transmission. It is also the case that any previously unsent | 104 // prepared for transmission. It is also the case that any previously unsent |
| 106 // logs have been loaded into instance variables for possible transmission. | 105 // logs have been loaded into instance variables for possible transmission. |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 146 | 145 |
| 147 #include "base/bind.h" | 146 #include "base/bind.h" |
| 148 #include "base/callback.h" | 147 #include "base/callback.h" |
| 149 #include "base/command_line.h" | 148 #include "base/command_line.h" |
| 150 #include "base/md5.h" | 149 #include "base/md5.h" |
| 151 #include "base/metrics/histogram.h" | 150 #include "base/metrics/histogram.h" |
| 152 #include "base/string_number_conversions.h" | 151 #include "base/string_number_conversions.h" |
| 153 #include "base/threading/platform_thread.h" | 152 #include "base/threading/platform_thread.h" |
| 154 #include "base/threading/thread.h" | 153 #include "base/threading/thread.h" |
| 155 #include "base/threading/thread_restrictions.h" | 154 #include "base/threading/thread_restrictions.h" |
| 155 #include "base/time.h" | |
| 156 #include "base/tracked_objects.h" | 156 #include "base/tracked_objects.h" |
| 157 #include "base/utf_string_conversions.h" | 157 #include "base/utf_string_conversions.h" |
| 158 #include "base/values.h" | 158 #include "base/values.h" |
| 159 #include "chrome/browser/bookmarks/bookmark_model.h" | 159 #include "chrome/browser/bookmarks/bookmark_model.h" |
| 160 #include "chrome/browser/browser_process.h" | 160 #include "chrome/browser/browser_process.h" |
| 161 #include "chrome/browser/extensions/extension_service.h" | 161 #include "chrome/browser/extensions/extension_service.h" |
| 162 #include "chrome/browser/extensions/process_map.h" | 162 #include "chrome/browser/extensions/process_map.h" |
| 163 #include "chrome/browser/io_thread.h" | 163 #include "chrome/browser/io_thread.h" |
| 164 #include "chrome/browser/memory_details.h" | 164 #include "chrome/browser/memory_details.h" |
| 165 #include "chrome/browser/metrics/histogram_synchronizer.h" | 165 #include "chrome/browser/metrics/histogram_synchronizer.h" |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 222 const char kMetricsTypeProto[] = "application/vnd.chrome.uma"; | 222 const char kMetricsTypeProto[] = "application/vnd.chrome.uma"; |
| 223 | 223 |
| 224 const char kServerUrlXml[] = | 224 const char kServerUrlXml[] = |
| 225 "https://clients4.google.com/firefox/metrics/collect"; | 225 "https://clients4.google.com/firefox/metrics/collect"; |
| 226 const char kServerUrlProto[] = "https://clients4.google.com/uma/v2"; | 226 const char kServerUrlProto[] = "https://clients4.google.com/uma/v2"; |
| 227 | 227 |
| 228 // The delay, in seconds, after starting recording before doing expensive | 228 // The delay, in seconds, after starting recording before doing expensive |
| 229 // initialization work. | 229 // initialization work. |
| 230 const int kInitializationDelaySeconds = 30; | 230 const int kInitializationDelaySeconds = 30; |
| 231 | 231 |
| 232 // The timeout, in seconds, to resume initialization of the MetricsService if | |
| 233 // the initialization of the StatisticsProvider hasn't completed yet. | |
| 234 const int kStatisticsProviderTimeoutSeconds = 300; | |
| 235 | |
| 232 // This specifies the amount of time to wait for all renderers to send their | 236 // This specifies the amount of time to wait for all renderers to send their |
| 233 // data. | 237 // data. |
| 234 const int kMaxHistogramGatheringWaitDuration = 60000; // 60 seconds. | 238 const int kMaxHistogramGatheringWaitDuration = 60000; // 60 seconds. |
| 235 | 239 |
| 236 // The maximum number of events in a log uploaded to the UMA server. | 240 // The maximum number of events in a log uploaded to the UMA server. |
| 237 const int kEventLimit = 2400; | 241 const int kEventLimit = 2400; |
| 238 | 242 |
| 239 // If an upload fails, and the transmission was over this byte count, then we | 243 // If an upload fails, and the transmission was over this byte count, then we |
| 240 // will discard the log, and not try to retransmit it. We also don't persist | 244 // will discard the log, and not try to retransmit it. We also don't persist |
| 241 // the log to the prefs for transmission during the next chrome session if this | 245 // the log to the prefs for transmission during the next chrome session if this |
| 242 // limit is exceeded. | 246 // limit is exceeded. |
| 243 const size_t kUploadLogAvoidRetransmitSize = 50000; | 247 const size_t kUploadLogAvoidRetransmitSize = 50000; |
| 244 | 248 |
| 245 // Interval, in minutes, between state saves. | 249 // Interval, in minutes, between state saves. |
| 246 const int kSaveStateIntervalMinutes = 5; | 250 const int kSaveStateIntervalMinutes = 5; |
| 247 | 251 |
| 248 // Used to indicate that the response code is currently not set at all -- | 252 // Used to indicate that the response code is currently not set at all -- |
| 249 // RESPONSE_CODE_INVALID can sometimes be returned in response to a request if, | 253 // RESPONSE_CODE_INVALID can sometimes be returned in response to a request if, |
| 250 // e.g., the server is down. | 254 // e.g., the server is down. |
| 251 const int kNoResponseCode = content::URLFetcher::RESPONSE_CODE_INVALID - 1; | 255 const int kNoResponseCode = content::URLFetcher::RESPONSE_CODE_INVALID - 1; |
| 252 | 256 |
| 257 // Used to indicate that a report was generated before the hardware_class | |
| 258 // property was available from the StatisticsProvider. This is used to identify | |
| 259 // faulty reports from Chrome OS clients. | |
| 260 const char kHardwareClassNotReady[] = "(not ready)"; | |
| 261 | |
| 253 } | 262 } |
| 254 | 263 |
| 255 // static | 264 // static |
| 256 MetricsService::ShutdownCleanliness MetricsService::clean_shutdown_status_ = | 265 MetricsService::ShutdownCleanliness MetricsService::clean_shutdown_status_ = |
| 257 MetricsService::CLEANLY_SHUTDOWN; | 266 MetricsService::CLEANLY_SHUTDOWN; |
| 258 | 267 |
| 259 // This is used to quickly log stats from child process related notifications in | 268 // This is used to quickly log stats from child process related notifications in |
| 260 // MetricsService::child_stats_buffer_. The buffer's contents are transferred | 269 // MetricsService::child_stats_buffer_. The buffer's contents are transferred |
| 261 // out when Local State is periodically saved. The information is then | 270 // out when Local State is periodically saved. The information is then |
| 262 // reported to the UMA server on next launch. | 271 // reported to the UMA server on next launch. |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 393 } | 402 } |
| 394 | 403 |
| 395 MetricsService::MetricsService() | 404 MetricsService::MetricsService() |
| 396 : recording_active_(false), | 405 : recording_active_(false), |
| 397 reporting_active_(false), | 406 reporting_active_(false), |
| 398 state_(INITIALIZED), | 407 state_(INITIALIZED), |
| 399 idle_since_last_transmission_(false), | 408 idle_since_last_transmission_(false), |
| 400 next_window_id_(0), | 409 next_window_id_(0), |
| 401 ALLOW_THIS_IN_INITIALIZER_LIST(self_ptr_factory_(this)), | 410 ALLOW_THIS_IN_INITIALIZER_LIST(self_ptr_factory_(this)), |
| 402 ALLOW_THIS_IN_INITIALIZER_LIST(state_saver_factory_(this)), | 411 ALLOW_THIS_IN_INITIALIZER_LIST(state_saver_factory_(this)), |
| 412 ALLOW_THIS_IN_INITIALIZER_LIST(timeout_task_factory_(this)), | |
| 403 waiting_for_asynchronus_reporting_step_(false) { | 413 waiting_for_asynchronus_reporting_step_(false) { |
| 404 DCHECK(IsSingleThreaded()); | 414 DCHECK(IsSingleThreaded()); |
| 405 InitializeMetricsState(); | 415 InitializeMetricsState(); |
| 406 | 416 |
| 407 base::Closure callback = base::Bind(&MetricsService::StartScheduledUpload, | 417 base::Closure callback = base::Bind(&MetricsService::StartScheduledUpload, |
| 408 self_ptr_factory_.GetWeakPtr()); | 418 self_ptr_factory_.GetWeakPtr()); |
| 409 scheduler_.reset(new MetricsReportingScheduler(callback)); | 419 scheduler_.reset(new MetricsReportingScheduler(callback)); |
| 410 log_manager_.set_log_serializer(new MetricsLogSerializer()); | 420 log_manager_.set_log_serializer(new MetricsLogSerializer()); |
| 411 log_manager_.set_max_ongoing_log_store_size(kUploadLogAvoidRetransmitSize); | 421 log_manager_.set_max_ongoing_log_store_size(kUploadLogAvoidRetransmitSize); |
| 412 } | 422 } |
| (...skipping 337 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 750 size_t switch_count = command_line->GetSwitches().size(); | 760 size_t switch_count = command_line->GetSwitches().size(); |
| 751 UMA_HISTOGRAM_COUNTS_100("Chrome.CommandLineFlagCount", switch_count); | 761 UMA_HISTOGRAM_COUNTS_100("Chrome.CommandLineFlagCount", switch_count); |
| 752 UMA_HISTOGRAM_COUNTS_100("Chrome.CommandLineUncommonFlagCount", | 762 UMA_HISTOGRAM_COUNTS_100("Chrome.CommandLineUncommonFlagCount", |
| 753 switch_count - common_commands); | 763 switch_count - common_commands); |
| 754 | 764 |
| 755 // Kick off the process of saving the state (so the uptime numbers keep | 765 // Kick off the process of saving the state (so the uptime numbers keep |
| 756 // getting updated) every n minutes. | 766 // getting updated) every n minutes. |
| 757 ScheduleNextStateSave(); | 767 ScheduleNextStateSave(); |
| 758 } | 768 } |
| 759 | 769 |
| 760 // static | 770 void MetricsService::InitTaskGetHardwareClass() { |
| 761 void MetricsService::InitTaskGetHardwareClass( | 771 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 762 base::WeakPtr<MetricsService> self, | 772 DCHECK_EQ(INIT_TASK_SCHEDULED, state_); |
| 763 base::MessageLoopProxy* target_loop) { | |
| 764 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
| 765 | 773 |
| 766 std::string hardware_class; | |
| 767 #if defined(OS_CHROMEOS) | 774 #if defined(OS_CHROMEOS) |
| 768 chromeos::system::StatisticsProvider::GetInstance()->GetMachineStatistic( | 775 // The hardware class can only be retrieved once the StatisticsProvider is |
| 769 "hardware_class", &hardware_class); | 776 // ready. This usually happens early enough, but can take longer on some |
| 770 #endif // OS_CHROMEOS | 777 // faulty hardware. |
| 778 chromeos::system::StatisticsProvider::GetInstance()->WhenReady( | |
| 779 base::Bind(&MetricsService::OnStatisticsProviderReady, | |
| 780 self_ptr_factory_.GetWeakPtr(), | |
| 781 base::Time::Now())); | |
| 771 | 782 |
| 772 target_loop->PostTask(FROM_HERE, | 783 // Set up a timeout task in case the StatisticsProvider takes too long to |
| 773 base::Bind(&MetricsService::OnInitTaskGotHardwareClass, | 784 // initialize. Only one of these tasks will execute; invoking either |
| 774 self, hardware_class)); | 785 // invalidates the WeakPtr of the other. In both cases, hardware_class_ is |
| 786 // updated once OnStatisticsProviderReady is invoked. | |
| 787 | |
| 788 // Invoke the next init task if the StatisticsProvider becomes ready. | |
| 789 // This will be invoked immediately after OnStatisticsProviderReady. | |
| 790 chromeos::system::StatisticsProvider::GetInstance()->WhenReady( | |
| 791 base::Bind(&MetricsService::InitTaskGetPluginInfo, | |
| 792 timeout_task_factory_.GetWeakPtr())); | |
| 793 | |
| 794 // Invoke OnStatisticsProviderTimeout if it times out instead. | |
| 795 MessageLoop::current()->PostDelayedTask( | |
| 796 FROM_HERE, | |
| 797 base::Bind(&MetricsService::OnStatisticsProviderTimeout, | |
| 798 timeout_task_factory_.GetWeakPtr()), | |
| 799 base::TimeDelta::FromSeconds(kStatisticsProviderTimeoutSeconds)); | |
| 800 #else | |
| 801 InitTaskGetPluginInfo(); | |
| 802 #endif | |
| 775 } | 803 } |
| 776 | 804 |
| 777 void MetricsService::OnInitTaskGotHardwareClass( | 805 void MetricsService::OnStatisticsProviderReady(const base::Time& start_time) { |
| 778 const std::string& hardware_class) { | 806 #if defined(OS_CHROMEOS) |
| 807 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 808 base::TimeDelta elapsed = base::Time::Now() - start_time; | |
| 809 UMA_HISTOGRAM_LONG_TIMES("UMA.StatisticsProviderReadyDelay", elapsed); | |
| 810 chromeos::system::StatisticsProvider::GetInstance()->GetMachineStatistic( | |
| 811 "hardware_class", &hardware_class_); | |
| 812 #endif | |
| 813 } | |
| 814 | |
| 815 void MetricsService::OnStatisticsProviderTimeout() { | |
|
Ilya Sherman
2012/04/30 07:36:41
nit: Perhaps log a histogram/event for the timeout
Joao da Silva
2012/05/15 13:52:47
Good idea. I've moved these histograms to the Stat
| |
| 816 #if defined(OS_CHROMEOS) | |
| 817 // Use an invalid hardware_class temporarily until the StatisticsProvider is | |
| 818 // ready. | |
|
Ilya Sherman
2012/04/30 07:36:41
It looks like, with this setup, we'll never record
Joao da Silva
2012/05/15 13:52:47
The WhenReady() callback is still pending in this
| |
| 819 hardware_class_ = kHardwareClassNotReady; | |
| 820 InitTaskGetPluginInfo(); | |
| 821 #endif | |
| 822 } | |
| 823 | |
| 824 void MetricsService::InitTaskGetPluginInfo() { | |
| 825 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 779 DCHECK_EQ(INIT_TASK_SCHEDULED, state_); | 826 DCHECK_EQ(INIT_TASK_SCHEDULED, state_); |
| 780 hardware_class_ = hardware_class; | 827 |
| 828 // Invalidate tasks related to waiting for the StatisticsProvider to | |
| 829 // initialize, if any are still scheduled. | |
| 830 timeout_task_factory_.InvalidateWeakPtrs(); | |
| 781 | 831 |
| 782 // Start the next part of the init task: loading plugin information. | 832 // Start the next part of the init task: loading plugin information. |
| 783 PluginService::GetInstance()->GetPlugins( | 833 PluginService::GetInstance()->GetPlugins( |
| 784 base::Bind(&MetricsService::OnInitTaskGotPluginInfo, | 834 base::Bind(&MetricsService::OnInitTaskGotPluginInfo, |
| 785 self_ptr_factory_.GetWeakPtr())); | 835 self_ptr_factory_.GetWeakPtr())); |
| 786 } | 836 } |
| 787 | 837 |
| 788 void MetricsService::OnInitTaskGotPluginInfo( | 838 void MetricsService::OnInitTaskGotPluginInfo( |
| 789 const std::vector<webkit::WebPluginInfo>& plugins) { | 839 const std::vector<webkit::WebPluginInfo>& plugins) { |
| 790 DCHECK_EQ(INIT_TASK_SCHEDULED, state_); | 840 DCHECK_EQ(INIT_TASK_SCHEDULED, state_); |
| 791 plugins_ = plugins; | 841 plugins_ = plugins; |
| 792 | 842 |
| 793 // Start the next part of the init task: fetching performance data. This will | 843 // Start the next part of the init task: fetching performance data. This will |
| 794 // call into |FinishedReceivingProfilerData()| when the task completes. | 844 // call into |FinishedReceivingProfilerData()| when the task completes. |
| 795 chrome_browser_metrics::TrackingSynchronizer::FetchProfilerDataAsynchronously( | 845 chrome_browser_metrics::TrackingSynchronizer::FetchProfilerDataAsynchronously( |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 850 void MetricsService::StartRecording() { | 900 void MetricsService::StartRecording() { |
| 851 if (log_manager_.current_log()) | 901 if (log_manager_.current_log()) |
| 852 return; | 902 return; |
| 853 | 903 |
| 854 log_manager_.BeginLoggingWithLog(new MetricsLog(client_id_, session_id_), | 904 log_manager_.BeginLoggingWithLog(new MetricsLog(client_id_, session_id_), |
| 855 MetricsLogManager::ONGOING_LOG); | 905 MetricsLogManager::ONGOING_LOG); |
| 856 if (state_ == INITIALIZED) { | 906 if (state_ == INITIALIZED) { |
| 857 // We only need to schedule that run once. | 907 // We only need to schedule that run once. |
| 858 state_ = INIT_TASK_SCHEDULED; | 908 state_ = INIT_TASK_SCHEDULED; |
| 859 | 909 |
| 860 // Schedules a task on the file thread for execution of slower | 910 // Schedules a delayed task for execution of slower initialization steps |
| 861 // initialization steps (such as plugin list generation) necessary | 911 // (such as plugin list generation) necessary for sending the initial log. |
| 862 // for sending the initial log. This avoids blocking the main UI | 912 MessageLoop::current()->PostDelayedTask( |
| 863 // thread. | |
| 864 BrowserThread::PostDelayedTask( | |
| 865 BrowserThread::FILE, | |
| 866 FROM_HERE, | 913 FROM_HERE, |
| 867 base::Bind(&MetricsService::InitTaskGetHardwareClass, | 914 base::Bind(&MetricsService::InitTaskGetHardwareClass, |
| 868 self_ptr_factory_.GetWeakPtr(), | 915 self_ptr_factory_.GetWeakPtr()), |
| 869 MessageLoop::current()->message_loop_proxy()), | |
| 870 base::TimeDelta::FromSeconds(kInitializationDelaySeconds)); | 916 base::TimeDelta::FromSeconds(kInitializationDelaySeconds)); |
| 871 } | 917 } |
| 872 } | 918 } |
| 873 | 919 |
| 874 void MetricsService::StopRecording() { | 920 void MetricsService::StopRecording() { |
| 875 if (!log_manager_.current_log()) | 921 if (!log_manager_.current_log()) |
| 876 return; | 922 return; |
| 877 | 923 |
| 878 // TODO(jar): Integrate bounds on log recording more consistently, so that we | 924 // TODO(jar): Integrate bounds on log recording more consistently, so that we |
| 879 // can stop recording logs that are too big much sooner. | 925 // can stop recording logs that are too big much sooner. |
| (...skipping 816 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1696 if (local_state) { | 1742 if (local_state) { |
| 1697 const PrefService::Preference* uma_pref = | 1743 const PrefService::Preference* uma_pref = |
| 1698 local_state->FindPreference(prefs::kMetricsReportingEnabled); | 1744 local_state->FindPreference(prefs::kMetricsReportingEnabled); |
| 1699 if (uma_pref) { | 1745 if (uma_pref) { |
| 1700 bool success = uma_pref->GetValue()->GetAsBoolean(&result); | 1746 bool success = uma_pref->GetValue()->GetAsBoolean(&result); |
| 1701 DCHECK(success); | 1747 DCHECK(success); |
| 1702 } | 1748 } |
| 1703 } | 1749 } |
| 1704 return result; | 1750 return result; |
| 1705 } | 1751 } |
| OLD | NEW |