OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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 | 6 |
7 //------------------------------------------------------------------------------ | 7 //------------------------------------------------------------------------------ |
8 // Description of the life cycle of a instance of MetricsService. | 8 // Description of the life cycle of a instance of MetricsService. |
9 // | 9 // |
10 // OVERVIEW | 10 // OVERVIEW |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
75 // shutdown," involves the deliberate user termination of the process before | 75 // shutdown," involves the deliberate user termination of the process before |
76 // the initial log is even formed or transmitted. In that situation, no logging | 76 // the initial log is even formed or transmitted. In that situation, no logging |
77 // is done, but the historical crash statistics remain (unlogged) for inclusion | 77 // is done, but the historical crash statistics remain (unlogged) for inclusion |
78 // in a future run's initial log. (i.e., we don't lose crash stats). | 78 // in a future run's initial log. (i.e., we don't lose crash stats). |
79 // | 79 // |
80 // With the above overview, we can now describe the state machine's various | 80 // With the above overview, we can now describe the state machine's various |
81 // stats, based on the State enum specified in the state_ member. Those states | 81 // stats, based on the State enum specified in the state_ member. Those states |
82 // are: | 82 // are: |
83 // | 83 // |
84 // INITIALIZED, // Constructor was called. | 84 // INITIALIZED, // Constructor was called. |
85 // PLUGIN_LIST_REQUESTED, // Waiting for plugin list to be loaded. | 85 // INIT_TASK_SCHEDULED, // Waiting for deferred init tasks to complete. |
86 // PLUGIN_LIST_ARRIVED, // Waiting for timer to send initial log. | 86 // INIT_TASK_DONE, // Waiting for timer to send initial log. |
87 // INITIAL_LOG_READY, // Initial log generated, and waiting for reply. | 87 // INITIAL_LOG_READY, // Initial log generated, and waiting for reply. |
88 // SEND_OLD_INITIAL_LOGS, // Sending unsent logs from previous session. | 88 // SEND_OLD_INITIAL_LOGS, // Sending unsent logs from previous session. |
89 // SENDING_OLD_LOGS, // Sending unsent logs from previous session. | 89 // SENDING_OLD_LOGS, // Sending unsent logs from previous session. |
90 // SENDING_CURRENT_LOGS, // Sending standard current logs as they accrue. | 90 // SENDING_CURRENT_LOGS, // Sending standard current logs as they accrue. |
91 // | 91 // |
92 // In more detail, we have: | 92 // In more detail, we have: |
93 // | 93 // |
94 // INITIALIZED, // Constructor was called. | 94 // INITIALIZED, // Constructor was called. |
95 // The MS has been constructed, but has taken no actions to compose the | 95 // The MS has been constructed, but has taken no actions to compose the |
96 // initial log. | 96 // initial log. |
97 // | 97 // |
98 // PLUGIN_LIST_REQUESTED, // Waiting for plugin list to be loaded. | 98 // INIT_TASK_SCHEDULED, // Waiting for deferred init tasks to complete. |
99 // Typically about 30 seconds after startup, a task is sent to a second thread | 99 // Typically about 30 seconds after startup, a task is sent to a second thread |
100 // to get the list of plugins. That task will (when complete) make an async | 100 // (the file thread) to perform deferred (lower priority and slower) |
101 // callback (via a Task) to indicate the completion. | 101 // initialization steps such as getting the list of plugins. That task will |
| 102 // (when complete) make an async callback (via a Task) to indicate the |
| 103 // completion. |
102 // | 104 // |
103 // PLUGIN_LIST_ARRIVED, // Waiting for timer to send initial log. | 105 // INIT_TASK_DONE, // Waiting for timer to send initial log. |
104 // The callback has arrived, and it is now possible for an initial log to be | 106 // The callback has arrived, and it is now possible for an initial log to be |
105 // created. This callback typically arrives back less than one second after | 107 // created. This callback typically arrives back less than one second after |
106 // the task is dispatched. | 108 // the deferred init task is dispatched. |
107 // | 109 // |
108 // INITIAL_LOG_READY, // Initial log generated, and waiting for reply. | 110 // INITIAL_LOG_READY, // Initial log generated, and waiting for reply. |
109 // This state is entered only after an initial log has been composed, and | 111 // This state is entered only after an initial log has been composed, and |
110 // prepared for transmission. It is also the case that any previously unsent | 112 // prepared for transmission. It is also the case that any previously unsent |
111 // logs have been loaded into instance variables for possible transmission. | 113 // logs have been loaded into instance variables for possible transmission. |
112 // | 114 // |
113 // SEND_OLD_INITIAL_LOGS, // Sending unsent logs from previous session. | 115 // SEND_OLD_INITIAL_LOGS, // Sending unsent logs from previous session. |
114 // This state indicates that the initial log for this session has been | 116 // This state indicates that the initial log for this session has been |
115 // successfully sent and it is now time to send any "initial logs" that were | 117 // successfully sent and it is now time to send any "initial logs" that were |
116 // saved from previous sessions. Most commonly, there are none, but all old | 118 // saved from previous sessions. Most commonly, there are none, but all old |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
190 #include "base/rand_util.h" | 192 #include "base/rand_util.h" |
191 #endif | 193 #endif |
192 | 194 |
193 // TODO(port): port browser_distribution.h. | 195 // TODO(port): port browser_distribution.h. |
194 #if !defined(OS_POSIX) | 196 #if !defined(OS_POSIX) |
195 #include "chrome/installer/util/browser_distribution.h" | 197 #include "chrome/installer/util/browser_distribution.h" |
196 #endif | 198 #endif |
197 | 199 |
198 #if defined(OS_CHROMEOS) | 200 #if defined(OS_CHROMEOS) |
199 #include "chrome/browser/chromeos/external_metrics.h" | 201 #include "chrome/browser/chromeos/external_metrics.h" |
| 202 |
| 203 static const char kHardwareClassTool[] = "/usr/bin/hardware_class"; |
| 204 static const char kUnknownHardwareClass[] = "unknown"; |
200 #endif | 205 #endif |
201 | 206 |
202 using base::Time; | 207 using base::Time; |
203 using base::TimeDelta; | 208 using base::TimeDelta; |
204 | 209 |
205 // Check to see that we're being called on only one thread. | 210 // Check to see that we're being called on only one thread. |
206 static bool IsSingleThreaded(); | 211 static bool IsSingleThreaded(); |
207 | 212 |
208 static const char kMetricsType[] = "application/vnd.mozilla.metrics.bz2"; | 213 static const char kMetricsType[] = "application/vnd.mozilla.metrics.bz2"; |
209 | 214 |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
275 MessageLoop::current()->PostTask(FROM_HERE, completion_); | 280 MessageLoop::current()->PostTask(FROM_HERE, completion_); |
276 } | 281 } |
277 | 282 |
278 private: | 283 private: |
279 ~MetricsMemoryDetails() {} | 284 ~MetricsMemoryDetails() {} |
280 | 285 |
281 Task* completion_; | 286 Task* completion_; |
282 DISALLOW_EVIL_CONSTRUCTORS(MetricsMemoryDetails); | 287 DISALLOW_EVIL_CONSTRUCTORS(MetricsMemoryDetails); |
283 }; | 288 }; |
284 | 289 |
285 class MetricsService::GetPluginListTaskComplete : public Task { | 290 class MetricsService::InitTaskComplete : public Task { |
286 public: | 291 public: |
287 explicit GetPluginListTaskComplete( | 292 explicit InitTaskComplete(const std::string& hardware_class, |
288 const std::vector<WebPluginInfo>& plugins) : plugins_(plugins) { } | 293 const std::vector<WebPluginInfo>& plugins) |
| 294 : hardware_class_(hardware_class), plugins_(plugins) {} |
| 295 |
289 virtual void Run() { | 296 virtual void Run() { |
290 g_browser_process->metrics_service()->OnGetPluginListTaskComplete(plugins_); | 297 g_browser_process->metrics_service()->OnInitTaskComplete( |
| 298 hardware_class_, plugins_); |
291 } | 299 } |
292 | 300 |
293 private: | 301 private: |
| 302 std::string hardware_class_; |
294 std::vector<WebPluginInfo> plugins_; | 303 std::vector<WebPluginInfo> plugins_; |
295 }; | 304 }; |
296 | 305 |
297 class MetricsService::GetPluginListTask : public Task { | 306 class MetricsService::InitTask : public Task { |
298 public: | 307 public: |
299 explicit GetPluginListTask(MessageLoop* callback_loop) | 308 explicit InitTask(MessageLoop* callback_loop) |
300 : callback_loop_(callback_loop) {} | 309 : callback_loop_(callback_loop) {} |
301 | 310 |
302 virtual void Run() { | 311 virtual void Run() { |
303 std::vector<WebPluginInfo> plugins; | 312 std::vector<WebPluginInfo> plugins; |
304 NPAPI::PluginList::Singleton()->GetPlugins(false, &plugins); | 313 NPAPI::PluginList::Singleton()->GetPlugins(false, &plugins); |
305 | 314 std::string hardware_class; // Empty string by default. |
306 callback_loop_->PostTask( | 315 #if defined(OS_CHROMEOS) |
307 FROM_HERE, new GetPluginListTaskComplete(plugins)); | 316 hardware_class = MetricsService::GetHardwareClass(); |
| 317 #endif // OS_CHROMEOS |
| 318 callback_loop_->PostTask(FROM_HERE, new InitTaskComplete( |
| 319 hardware_class, plugins)); |
308 } | 320 } |
309 | 321 |
310 private: | 322 private: |
311 MessageLoop* callback_loop_; | 323 MessageLoop* callback_loop_; |
312 }; | 324 }; |
313 | 325 |
314 // static | 326 // static |
315 void MetricsService::RegisterPrefs(PrefService* local_state) { | 327 void MetricsService::RegisterPrefs(PrefService* local_state) { |
316 DCHECK(IsSingleThreaded()); | 328 DCHECK(IsSingleThreaded()); |
317 local_state->RegisterStringPref(prefs::kMetricsClientID, L""); | 329 local_state->RegisterStringPref(prefs::kMetricsClientID, L""); |
(...skipping 420 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
738 UMA_HISTOGRAM_COUNTS_100("Chrome.CommandLineFlagCount", | 750 UMA_HISTOGRAM_COUNTS_100("Chrome.CommandLineFlagCount", |
739 command_line->GetSwitchCount()); | 751 command_line->GetSwitchCount()); |
740 UMA_HISTOGRAM_COUNTS_100("Chrome.CommandLineUncommonFlagCount", | 752 UMA_HISTOGRAM_COUNTS_100("Chrome.CommandLineUncommonFlagCount", |
741 command_line->GetSwitchCount() - common_commands); | 753 command_line->GetSwitchCount() - common_commands); |
742 | 754 |
743 // Kick off the process of saving the state (so the uptime numbers keep | 755 // Kick off the process of saving the state (so the uptime numbers keep |
744 // getting updated) every n minutes. | 756 // getting updated) every n minutes. |
745 ScheduleNextStateSave(); | 757 ScheduleNextStateSave(); |
746 } | 758 } |
747 | 759 |
748 void MetricsService::OnGetPluginListTaskComplete( | 760 void MetricsService::OnInitTaskComplete( |
| 761 const std::string& hardware_class, |
749 const std::vector<WebPluginInfo>& plugins) { | 762 const std::vector<WebPluginInfo>& plugins) { |
750 DCHECK(state_ == PLUGIN_LIST_REQUESTED); | 763 DCHECK(state_ == INIT_TASK_SCHEDULED); |
| 764 hardware_class_ = hardware_class; |
751 plugins_ = plugins; | 765 plugins_ = plugins; |
752 if (state_ == PLUGIN_LIST_REQUESTED) | 766 if (state_ == INIT_TASK_SCHEDULED) |
753 state_ = PLUGIN_LIST_ARRIVED; | 767 state_ = INIT_TASK_DONE; |
754 } | 768 } |
755 | 769 |
756 std::string MetricsService::GenerateClientID() { | 770 std::string MetricsService::GenerateClientID() { |
757 #if defined(OS_WIN) | 771 #if defined(OS_WIN) |
758 const int kGUIDSize = 39; | 772 const int kGUIDSize = 39; |
759 | 773 |
760 GUID guid; | 774 GUID guid; |
761 HRESULT guid_result = CoCreateGuid(&guid); | 775 HRESULT guid_result = CoCreateGuid(&guid); |
762 DCHECK(SUCCEEDED(guid_result)); | 776 DCHECK(SUCCEEDED(guid_result)); |
763 | 777 |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
815 //------------------------------------------------------------------------------ | 829 //------------------------------------------------------------------------------ |
816 // Recording control methods | 830 // Recording control methods |
817 | 831 |
818 void MetricsService::StartRecording() { | 832 void MetricsService::StartRecording() { |
819 if (current_log_) | 833 if (current_log_) |
820 return; | 834 return; |
821 | 835 |
822 current_log_ = new MetricsLog(client_id_, session_id_); | 836 current_log_ = new MetricsLog(client_id_, session_id_); |
823 if (state_ == INITIALIZED) { | 837 if (state_ == INITIALIZED) { |
824 // We only need to schedule that run once. | 838 // We only need to schedule that run once. |
825 state_ = PLUGIN_LIST_REQUESTED; | 839 state_ = INIT_TASK_SCHEDULED; |
826 | 840 |
827 // Make sure the plugin list is loaded before the inital log is sent, so | 841 // Schedules a task on the file thread for execution of slower |
828 // that the main thread isn't blocked generating the list. | 842 // initialization steps (such as plugin list generation) necessary |
| 843 // for sending the initial log. This avoids blocking the main UI |
| 844 // thread. |
829 g_browser_process->file_thread()->message_loop()->PostDelayedTask(FROM_HERE, | 845 g_browser_process->file_thread()->message_loop()->PostDelayedTask(FROM_HERE, |
830 new GetPluginListTask(MessageLoop::current()), | 846 new InitTask(MessageLoop::current()), |
831 kInitialInterlogDuration * 1000 / 2); | 847 kInitialInterlogDuration * 1000 / 2); |
832 } | 848 } |
833 } | 849 } |
834 | 850 |
835 void MetricsService::StopRecording(MetricsLog** log) { | 851 void MetricsService::StopRecording(MetricsLog** log) { |
836 if (!current_log_) | 852 if (!current_log_) |
837 return; | 853 return; |
838 | 854 |
| 855 current_log_->set_hardware_class(hardware_class_); // Adds to ongoing logs. |
| 856 |
839 // TODO(jar): Integrate bounds on log recording more consistently, so that we | 857 // TODO(jar): Integrate bounds on log recording more consistently, so that we |
840 // can stop recording logs that are too big much sooner. | 858 // can stop recording logs that are too big much sooner. |
841 if (current_log_->num_events() > log_event_limit_) { | 859 if (current_log_->num_events() > log_event_limit_) { |
842 UMA_HISTOGRAM_COUNTS("UMA.Discarded Log Events", | 860 UMA_HISTOGRAM_COUNTS("UMA.Discarded Log Events", |
843 current_log_->num_events()); | 861 current_log_->num_events()); |
844 current_log_->CloseLog(); | 862 current_log_->CloseLog(); |
845 delete current_log_; | 863 delete current_log_; |
846 current_log_ = NULL; | 864 current_log_ = NULL; |
847 StartRecording(); // Start trivial log to hold our histograms. | 865 StartRecording(); // Start trivial log to hold our histograms. |
848 } | 866 } |
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1043 HandleIdleSinceLastTransmission(true); | 1061 HandleIdleSinceLastTransmission(true); |
1044 } | 1062 } |
1045 | 1063 |
1046 | 1064 |
1047 void MetricsService::MakePendingLog() { | 1065 void MetricsService::MakePendingLog() { |
1048 if (pending_log()) | 1066 if (pending_log()) |
1049 return; | 1067 return; |
1050 | 1068 |
1051 switch (state_) { | 1069 switch (state_) { |
1052 case INITIALIZED: | 1070 case INITIALIZED: |
1053 case PLUGIN_LIST_REQUESTED: // We should be further along by now. | 1071 case INIT_TASK_SCHEDULED: // We should be further along by now. |
1054 DCHECK(false); | 1072 DCHECK(false); |
1055 return; | 1073 return; |
1056 | 1074 |
1057 case PLUGIN_LIST_ARRIVED: | 1075 case INIT_TASK_DONE: |
1058 // We need to wait for the initial log to be ready before sending | 1076 // We need to wait for the initial log to be ready before sending |
1059 // anything, because the server will tell us whether it wants to hear | 1077 // anything, because the server will tell us whether it wants to hear |
1060 // from us. | 1078 // from us. |
1061 PrepareInitialLog(); | 1079 PrepareInitialLog(); |
1062 DCHECK(state_ == PLUGIN_LIST_ARRIVED); | 1080 DCHECK(state_ == INIT_TASK_DONE); |
1063 RecallUnsentLogs(); | 1081 RecallUnsentLogs(); |
1064 state_ = INITIAL_LOG_READY; | 1082 state_ = INITIAL_LOG_READY; |
1065 break; | 1083 break; |
1066 | 1084 |
1067 case SEND_OLD_INITIAL_LOGS: | 1085 case SEND_OLD_INITIAL_LOGS: |
1068 if (!unsent_initial_logs_.empty()) { | 1086 if (!unsent_initial_logs_.empty()) { |
1069 pending_log_text_ = unsent_initial_logs_.back(); | 1087 pending_log_text_ = unsent_initial_logs_.back(); |
1070 break; | 1088 break; |
1071 } | 1089 } |
1072 state_ = SENDING_OLD_LOGS; | 1090 state_ = SENDING_OLD_LOGS; |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1109 case SENDING_OLD_LOGS: | 1127 case SENDING_OLD_LOGS: |
1110 return true; | 1128 return true; |
1111 | 1129 |
1112 case SENDING_CURRENT_LOGS: | 1130 case SENDING_CURRENT_LOGS: |
1113 default: | 1131 default: |
1114 return false; | 1132 return false; |
1115 } | 1133 } |
1116 } | 1134 } |
1117 | 1135 |
1118 void MetricsService::PrepareInitialLog() { | 1136 void MetricsService::PrepareInitialLog() { |
1119 DCHECK(state_ == PLUGIN_LIST_ARRIVED); | 1137 DCHECK(state_ == INIT_TASK_DONE); |
1120 | 1138 |
1121 MetricsLog* log = new MetricsLog(client_id_, session_id_); | 1139 MetricsLog* log = new MetricsLog(client_id_, session_id_); |
| 1140 log->set_hardware_class(hardware_class_); // Adds to initial log. |
1122 log->RecordEnvironment(plugins_, profile_dictionary_.get()); | 1141 log->RecordEnvironment(plugins_, profile_dictionary_.get()); |
1123 | 1142 |
1124 // Histograms only get written to current_log_, so setup for the write. | 1143 // Histograms only get written to current_log_, so setup for the write. |
1125 MetricsLog* save_log = current_log_; | 1144 MetricsLog* save_log = current_log_; |
1126 current_log_ = log; | 1145 current_log_ = log; |
1127 RecordCurrentHistograms(); // Into current_log_... which is really log. | 1146 RecordCurrentHistograms(); // Into current_log_... which is really log. |
1128 current_log_ = save_log; | 1147 current_log_ = save_log; |
1129 | 1148 |
1130 log->CloseLog(); | 1149 log->CloseLog(); |
1131 DCHECK(!pending_log()); | 1150 DCHECK(!pending_log()); |
(...skipping 771 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1903 } | 1922 } |
1904 | 1923 |
1905 static bool IsSingleThreaded() { | 1924 static bool IsSingleThreaded() { |
1906 static PlatformThreadId thread_id = 0; | 1925 static PlatformThreadId thread_id = 0; |
1907 if (!thread_id) | 1926 if (!thread_id) |
1908 thread_id = PlatformThread::CurrentId(); | 1927 thread_id = PlatformThread::CurrentId(); |
1909 return PlatformThread::CurrentId() == thread_id; | 1928 return PlatformThread::CurrentId() == thread_id; |
1910 } | 1929 } |
1911 | 1930 |
1912 #if defined(OS_CHROMEOS) | 1931 #if defined(OS_CHROMEOS) |
| 1932 // static |
| 1933 std::string MetricsService::GetHardwareClass() { |
| 1934 DCHECK(!ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 1935 std::string hardware_class; |
| 1936 FilePath tool(kHardwareClassTool); |
| 1937 CommandLine command(tool); |
| 1938 if (base::GetAppOutput(command, &hardware_class)) { |
| 1939 TrimWhitespaceASCII(hardware_class, TRIM_ALL, &hardware_class); |
| 1940 } else { |
| 1941 hardware_class = kUnknownHardwareClass; |
| 1942 } |
| 1943 return hardware_class; |
| 1944 } |
| 1945 |
1913 void MetricsService::StartExternalMetrics() { | 1946 void MetricsService::StartExternalMetrics() { |
1914 external_metrics_ = new chromeos::ExternalMetrics; | 1947 external_metrics_ = new chromeos::ExternalMetrics; |
1915 external_metrics_->Start(); | 1948 external_metrics_->Start(); |
1916 } | 1949 } |
1917 #endif | 1950 #endif |
OLD | NEW |