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 800 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
811 } | 811 } |
812 | 812 |
813 | 813 |
814 //------------------------------------------------------------------------------ | 814 //------------------------------------------------------------------------------ |
815 // Recording control methods | 815 // Recording control methods |
816 | 816 |
817 void MetricsService::StartRecording() { | 817 void MetricsService::StartRecording() { |
818 if (log_manager_.current_log()) | 818 if (log_manager_.current_log()) |
819 return; | 819 return; |
820 | 820 |
821 log_manager_.BeginLoggingWithLog(new MetricsLog(client_id_, session_id_)); | 821 log_manager_.BeginLoggingWithLog(new MetricsLog(client_id_, session_id_), |
| 822 MetricsLogManager::ONGOING_LOG); |
822 if (state_ == INITIALIZED) { | 823 if (state_ == INITIALIZED) { |
823 // We only need to schedule that run once. | 824 // We only need to schedule that run once. |
824 state_ = INIT_TASK_SCHEDULED; | 825 state_ = INIT_TASK_SCHEDULED; |
825 | 826 |
826 // Schedules a task on the file thread for execution of slower | 827 // Schedules a task on the file thread for execution of slower |
827 // initialization steps (such as plugin list generation) necessary | 828 // initialization steps (such as plugin list generation) necessary |
828 // for sending the initial log. This avoids blocking the main UI | 829 // for sending the initial log. This avoids blocking the main UI |
829 // thread. | 830 // thread. |
830 BrowserThread::PostDelayedTask( | 831 BrowserThread::PostDelayedTask( |
831 BrowserThread::FILE, | 832 BrowserThread::FILE, |
(...skipping 24 matching lines...) Expand all Loading... |
856 // Put incremental data (histogram deltas, and realtime stats deltas) at the | 857 // Put incremental data (histogram deltas, and realtime stats deltas) at the |
857 // end of all log transmissions (initial log handles this separately). | 858 // end of all log transmissions (initial log handles this separately). |
858 // RecordIncrementalStabilityElements only exists on the derived | 859 // RecordIncrementalStabilityElements only exists on the derived |
859 // MetricsLog class. | 860 // MetricsLog class. |
860 MetricsLog* current_log = | 861 MetricsLog* current_log = |
861 static_cast<MetricsLog*>(log_manager_.current_log()); | 862 static_cast<MetricsLog*>(log_manager_.current_log()); |
862 DCHECK(current_log); | 863 DCHECK(current_log); |
863 current_log->RecordIncrementalStabilityElements(plugins_); | 864 current_log->RecordIncrementalStabilityElements(plugins_); |
864 RecordCurrentHistograms(); | 865 RecordCurrentHistograms(); |
865 | 866 |
866 log_manager_.StageCurrentLogForUpload(); | 867 log_manager_.FinishCurrentLog(); |
867 } | 868 } |
868 | 869 |
869 void MetricsService::PushPendingLogsToPersistentStorage() { | 870 void MetricsService::PushPendingLogsToPersistentStorage() { |
870 if (state_ < INITIAL_LOG_READY) | 871 if (state_ < INITIAL_LOG_READY) |
871 return; // We didn't and still don't have time to get plugin list etc. | 872 return; // We didn't and still don't have time to get plugin list etc. |
872 | 873 |
873 if (log_manager_.has_staged_log()) { | 874 if (log_manager_.has_staged_log()) { |
874 if (state_ == INITIAL_LOG_READY) { | 875 // We may race here, and send second copy of initial log later. |
875 // We may race here, and send second copy of initial log later. | 876 if (state_ == INITIAL_LOG_READY) |
876 log_manager_.StoreStagedLogAsUnsent(MetricsLogManager::INITIAL_LOG); | |
877 state_ = SENDING_OLD_LOGS; | 877 state_ = SENDING_OLD_LOGS; |
878 } else { | 878 log_manager_.StoreStagedLogAsUnsent(); |
879 // TODO(jar): Verify correctness in other states, including sending unsent | |
880 // initial logs. | |
881 log_manager_.StoreStagedLogAsUnsent(MetricsLogManager::ONGOING_LOG); | |
882 } | |
883 } | 879 } |
884 DCHECK(!log_manager_.has_staged_log()); | 880 DCHECK(!log_manager_.has_staged_log()); |
885 StopRecording(); | 881 StopRecording(); |
886 log_manager_.StoreStagedLogAsUnsent(MetricsLogManager::ONGOING_LOG); | |
887 StoreUnsentLogs(); | 882 StoreUnsentLogs(); |
888 } | 883 } |
889 | 884 |
890 //------------------------------------------------------------------------------ | 885 //------------------------------------------------------------------------------ |
891 // Transmission of logs methods | 886 // Transmission of logs methods |
892 | 887 |
893 void MetricsService::StartSchedulerIfNecessary() { | 888 void MetricsService::StartSchedulerIfNecessary() { |
894 if (reporting_active() && recording_active()) | 889 if (reporting_active() && recording_active()) |
895 scheduler_->Start(); | 890 scheduler_->Start(); |
896 } | 891 } |
897 | 892 |
898 void MetricsService::StartScheduledUpload() { | 893 void MetricsService::StartScheduledUpload() { |
899 // If reporting has been turned off, the scheduler doesn't need to run. | 894 // If reporting has been turned off, the scheduler doesn't need to run. |
900 if (!reporting_active() || !recording_active()) { | 895 if (!reporting_active() || !recording_active()) { |
901 scheduler_->Stop(); | 896 scheduler_->Stop(); |
902 scheduler_->UploadCancelled(); | 897 scheduler_->UploadCancelled(); |
903 return; | 898 return; |
904 } | 899 } |
905 | 900 |
| 901 StartFinalLogInfoCollection(); |
| 902 } |
| 903 |
| 904 void MetricsService::StartFinalLogInfoCollection() { |
| 905 // Begin the multi-step process of collecting memory usage histograms: |
| 906 // First spawn a task to collect the memory details; when that task is |
| 907 // finished, it will call OnMemoryDetailCollectionDone. That will in turn |
| 908 // call HistogramSynchronization to collect histograms from all renderers and |
| 909 // then call OnHistogramSynchronizationDone to continue processing. |
906 DCHECK(!waiting_for_asynchronus_reporting_step_); | 910 DCHECK(!waiting_for_asynchronus_reporting_step_); |
907 waiting_for_asynchronus_reporting_step_ = true; | 911 waiting_for_asynchronus_reporting_step_ = true; |
908 | 912 |
909 base::Closure callback = | 913 base::Closure callback = |
910 base::Bind(&MetricsService::OnMemoryDetailCollectionDone, | 914 base::Bind(&MetricsService::OnMemoryDetailCollectionDone, |
911 self_ptr_factory_.GetWeakPtr()); | 915 self_ptr_factory_.GetWeakPtr()); |
912 | 916 |
913 scoped_refptr<MetricsMemoryDetails> details( | 917 scoped_refptr<MetricsMemoryDetails> details( |
914 new MetricsMemoryDetails(callback)); | 918 new MetricsMemoryDetails(callback)); |
915 details->StartFetch(); | 919 details->StartFetch(); |
916 | 920 |
917 // Collect WebCore cache information to put into a histogram. | 921 // Collect WebCore cache information to put into a histogram. |
918 for (content::RenderProcessHost::iterator i( | 922 for (content::RenderProcessHost::iterator i( |
919 content::RenderProcessHost::AllHostsIterator()); | 923 content::RenderProcessHost::AllHostsIterator()); |
920 !i.IsAtEnd(); i.Advance()) | 924 !i.IsAtEnd(); i.Advance()) |
921 i.GetCurrentValue()->Send(new ChromeViewMsg_GetCacheResourceStats()); | 925 i.GetCurrentValue()->Send(new ChromeViewMsg_GetCacheResourceStats()); |
922 } | 926 } |
923 | 927 |
924 void MetricsService::OnMemoryDetailCollectionDone() { | 928 void MetricsService::OnMemoryDetailCollectionDone() { |
925 DCHECK(IsSingleThreaded()); | 929 DCHECK(IsSingleThreaded()); |
926 // This function should only be called as the callback from an ansynchronous | 930 // This function should only be called as the callback from an ansynchronous |
927 // step. | 931 // step. |
928 DCHECK(waiting_for_asynchronus_reporting_step_); | 932 DCHECK(waiting_for_asynchronus_reporting_step_); |
929 | 933 |
930 // Right before the UMA transmission gets started, there's one more thing we'd | |
931 // like to record: the histogram of memory usage, so we spawn a task to | |
932 // collect the memory details and when that task is finished, it will call | |
933 // OnMemoryDetailCollectionDone, which will call HistogramSynchronization to | |
934 // collect histograms from all renderers and then we will call | |
935 // OnHistogramSynchronizationDone to continue processing. | |
936 | |
937 // Create a callback_task for OnHistogramSynchronizationDone. | 934 // Create a callback_task for OnHistogramSynchronizationDone. |
938 base::Closure callback = base::Bind( | 935 base::Closure callback = base::Bind( |
939 &MetricsService::OnHistogramSynchronizationDone, | 936 &MetricsService::OnHistogramSynchronizationDone, |
940 self_ptr_factory_.GetWeakPtr()); | 937 self_ptr_factory_.GetWeakPtr()); |
941 | 938 |
942 base::StatisticsRecorder::CollectHistogramStats("Browser"); | 939 base::StatisticsRecorder::CollectHistogramStats("Browser"); |
943 | 940 |
944 // Set up the callback to task to call after we receive histograms from all | 941 // Set up the callback to task to call after we receive histograms from all |
945 // renderer processes. Wait time specifies how long to wait before absolutely | 942 // renderer processes. Wait time specifies how long to wait before absolutely |
946 // calling us back on the task. | 943 // calling us back on the task. |
947 HistogramSynchronizer::FetchRendererHistogramsAsynchronously( | 944 HistogramSynchronizer::FetchRendererHistogramsAsynchronously( |
948 MessageLoop::current(), callback, | 945 MessageLoop::current(), callback, |
949 kMaxHistogramGatheringWaitDuration); | 946 kMaxHistogramGatheringWaitDuration); |
950 } | 947 } |
951 | 948 |
952 void MetricsService::OnHistogramSynchronizationDone() { | 949 void MetricsService::OnHistogramSynchronizationDone() { |
953 DCHECK(IsSingleThreaded()); | 950 DCHECK(IsSingleThreaded()); |
| 951 // This function should only be called as the callback from an ansynchronous |
| 952 // step. |
| 953 DCHECK(waiting_for_asynchronus_reporting_step_); |
954 | 954 |
| 955 waiting_for_asynchronus_reporting_step_ = false; |
| 956 OnFinalLogInfoCollectionDone(); |
| 957 } |
| 958 |
| 959 void MetricsService::OnFinalLogInfoCollectionDone() { |
955 // If somehow there is a fetch in progress, we return and hope things work | 960 // If somehow there is a fetch in progress, we return and hope things work |
956 // out. The scheduler isn't informed since if this happens, the scheduler | 961 // out. The scheduler isn't informed since if this happens, the scheduler |
957 // will get a response from the upload. | 962 // will get a response from the upload. |
958 DCHECK(!current_fetch_xml_.get()); | 963 DCHECK(!current_fetch_xml_.get()); |
959 DCHECK(!current_fetch_proto_.get()); | 964 DCHECK(!current_fetch_proto_.get()); |
960 if (current_fetch_xml_.get() || current_fetch_proto_.get()) | 965 if (current_fetch_xml_.get() || current_fetch_proto_.get()) |
961 return; | 966 return; |
962 | 967 |
963 // This function should only be called as the callback from an ansynchronous | |
964 // step. | |
965 DCHECK(waiting_for_asynchronus_reporting_step_); | |
966 waiting_for_asynchronus_reporting_step_ = false; | |
967 | |
968 // If we're getting no notifications, then the log won't have much in it, and | 968 // If we're getting no notifications, then the log won't have much in it, and |
969 // it's possible the computer is about to go to sleep, so don't upload and | 969 // it's possible the computer is about to go to sleep, so don't upload and |
970 // stop the scheduler. | 970 // stop the scheduler. |
971 // Similarly, if logs should no longer be uploaded, stop here. | 971 // Similarly, if logs should no longer be uploaded, stop here. |
972 if (idle_since_last_transmission_ || | 972 if (idle_since_last_transmission_ || |
973 !recording_active() || !reporting_active()) { | 973 !recording_active() || !reporting_active()) { |
974 scheduler_->Stop(); | 974 scheduler_->Stop(); |
975 scheduler_->UploadCancelled(); | 975 scheduler_->UploadCancelled(); |
976 return; | 976 return; |
977 } | 977 } |
978 | 978 |
979 MakeStagedLog(); | 979 MakeStagedLog(); |
980 | 980 |
981 // MakeStagedLog should have prepared log text; if it didn't, skip this | 981 // MakeStagedLog should have prepared log text; if it didn't, skip this |
982 // upload and hope things work out next time. | 982 // upload and hope things work out next time. |
983 if (log_manager_.staged_log_text().empty()) { | 983 if (log_manager_.staged_log_text().empty()) { |
984 scheduler_->UploadCancelled(); | 984 scheduler_->UploadCancelled(); |
985 return; | 985 return; |
986 } | 986 } |
987 | 987 |
988 PrepareFetchWithStagedLog(); | 988 SendStagedLog(); |
989 | |
990 if (!current_fetch_xml_.get()) { | |
991 DCHECK(!current_fetch_proto_.get()); | |
992 // Compression failed, and log discarded :-/. | |
993 log_manager_.DiscardStagedLog(); | |
994 scheduler_->UploadCancelled(); | |
995 // TODO(jar): If compression failed, we should have created a tiny log and | |
996 // compressed that, so that we can signal that we're losing logs. | |
997 return; | |
998 } | |
999 // Currently, the staged log for the protobuf version of the data is discarded | |
1000 // after we create the URL request, so that there is no chance for | |
1001 // re-transmission in case the corresponding XML request fails. We will | |
1002 // handle protobuf failures more carefully once that becomes the main | |
1003 // pipeline, i.e. once we switch away from the XML pipeline. | |
1004 DCHECK(current_fetch_proto_.get() || !log_manager_.has_staged_log_proto()); | |
1005 | |
1006 DCHECK(!waiting_for_asynchronus_reporting_step_); | |
1007 | |
1008 waiting_for_asynchronus_reporting_step_ = true; | |
1009 current_fetch_xml_->Start(); | |
1010 if (current_fetch_proto_.get()) | |
1011 current_fetch_proto_->Start(); | |
1012 | |
1013 HandleIdleSinceLastTransmission(true); | |
1014 } | 989 } |
1015 | 990 |
1016 | |
1017 void MetricsService::MakeStagedLog() { | 991 void MetricsService::MakeStagedLog() { |
1018 if (log_manager_.has_staged_log()) | 992 if (log_manager_.has_staged_log()) |
1019 return; | 993 return; |
1020 | 994 |
1021 switch (state_) { | 995 switch (state_) { |
1022 case INITIALIZED: | 996 case INITIALIZED: |
1023 case INIT_TASK_SCHEDULED: // We should be further along by now. | 997 case INIT_TASK_SCHEDULED: // We should be further along by now. |
1024 DCHECK(false); | 998 DCHECK(false); |
1025 return; | 999 return; |
1026 | 1000 |
1027 case INIT_TASK_DONE: | 1001 case INIT_TASK_DONE: |
1028 // We need to wait for the initial log to be ready before sending | 1002 // We need to wait for the initial log to be ready before sending |
1029 // anything, because the server will tell us whether it wants to hear | 1003 // anything, because the server will tell us whether it wants to hear |
1030 // from us. | 1004 // from us. |
1031 PrepareInitialLog(); | 1005 PrepareInitialLog(); |
1032 DCHECK(state_ == INIT_TASK_DONE); | 1006 DCHECK(state_ == INIT_TASK_DONE); |
1033 log_manager_.LoadPersistedUnsentLogs(); | 1007 log_manager_.LoadPersistedUnsentLogs(); |
1034 state_ = INITIAL_LOG_READY; | 1008 state_ = INITIAL_LOG_READY; |
1035 break; | 1009 break; |
1036 | 1010 |
1037 case SENDING_OLD_LOGS: | 1011 case SENDING_OLD_LOGS: |
1038 if (log_manager_.has_unsent_logs()) { | 1012 if (log_manager_.has_unsent_logs()) { |
1039 log_manager_.StageNextStoredLogForUpload(); | 1013 log_manager_.StageNextLogForUpload(); |
1040 break; | 1014 break; |
1041 } | 1015 } |
1042 state_ = SENDING_CURRENT_LOGS; | 1016 state_ = SENDING_CURRENT_LOGS; |
1043 // Fall through. | 1017 // Fall through. |
1044 | 1018 |
1045 case SENDING_CURRENT_LOGS: | 1019 case SENDING_CURRENT_LOGS: |
1046 StopRecording(); | 1020 StopRecording(); |
1047 StartRecording(); | 1021 StartRecording(); |
| 1022 log_manager_.StageNextLogForUpload(); |
1048 break; | 1023 break; |
1049 | 1024 |
1050 default: | 1025 default: |
1051 NOTREACHED(); | 1026 NOTREACHED(); |
1052 return; | 1027 return; |
1053 } | 1028 } |
1054 | 1029 |
1055 DCHECK(log_manager_.has_staged_log()); | 1030 DCHECK(log_manager_.has_staged_log()); |
1056 } | 1031 } |
1057 | 1032 |
1058 void MetricsService::PrepareInitialLog() { | 1033 void MetricsService::PrepareInitialLog() { |
1059 DCHECK(state_ == INIT_TASK_DONE); | 1034 DCHECK(state_ == INIT_TASK_DONE); |
1060 | 1035 |
1061 MetricsLog* log = new MetricsLog(client_id_, session_id_); | 1036 MetricsLog* log = new MetricsLog(client_id_, session_id_); |
1062 log->set_hardware_class(hardware_class_); // Adds to initial log. | 1037 log->set_hardware_class(hardware_class_); // Adds to initial log. |
1063 log->RecordEnvironment(plugins_, profile_dictionary_.get()); | 1038 log->RecordEnvironment(plugins_, profile_dictionary_.get()); |
1064 | 1039 |
1065 // Histograms only get written to the current log, so make the new log current | 1040 // Histograms only get written to the current log, so make the new log current |
1066 // before writing them. | 1041 // before writing them. |
1067 log_manager_.PauseCurrentLog(); | 1042 log_manager_.PauseCurrentLog(); |
1068 log_manager_.BeginLoggingWithLog(log); | 1043 log_manager_.BeginLoggingWithLog(log, MetricsLogManager::INITIAL_LOG); |
1069 RecordCurrentHistograms(); | 1044 RecordCurrentHistograms(); |
| 1045 log_manager_.FinishCurrentLog(); |
| 1046 log_manager_.ResumePausedLog(); |
1070 | 1047 |
1071 DCHECK(!log_manager_.has_staged_log()); | 1048 DCHECK(!log_manager_.has_staged_log()); |
1072 log_manager_.StageCurrentLogForUpload(); | 1049 log_manager_.StageNextLogForUpload(); |
1073 log_manager_.ResumePausedLog(); | |
1074 } | 1050 } |
1075 | 1051 |
1076 void MetricsService::StoreUnsentLogs() { | 1052 void MetricsService::StoreUnsentLogs() { |
1077 if (state_ < INITIAL_LOG_READY) | 1053 if (state_ < INITIAL_LOG_READY) |
1078 return; // We never Recalled the prior unsent logs. | 1054 return; // We never Recalled the prior unsent logs. |
1079 | 1055 |
1080 log_manager_.PersistUnsentLogs(); | 1056 log_manager_.PersistUnsentLogs(); |
1081 } | 1057 } |
1082 | 1058 |
| 1059 void MetricsService::SendStagedLog() { |
| 1060 DCHECK(log_manager_.has_staged_log()); |
| 1061 |
| 1062 PrepareFetchWithStagedLog(); |
| 1063 |
| 1064 if (!current_fetch_xml_.get()) { |
| 1065 DCHECK(!current_fetch_proto_.get()); |
| 1066 // Compression failed, and log discarded :-/. |
| 1067 log_manager_.DiscardStagedLog(); |
| 1068 scheduler_->UploadCancelled(); |
| 1069 // TODO(jar): If compression failed, we should have created a tiny log and |
| 1070 // compressed that, so that we can signal that we're losing logs. |
| 1071 return; |
| 1072 } |
| 1073 // Currently, the staged log for the protobuf version of the data is discarded |
| 1074 // after we create the URL request, so that there is no chance for |
| 1075 // re-transmission in case the corresponding XML request fails. We will |
| 1076 // handle protobuf failures more carefully once that becomes the main |
| 1077 // pipeline, i.e. once we switch away from the XML pipeline. |
| 1078 DCHECK(current_fetch_proto_.get() || !log_manager_.has_staged_log_proto()); |
| 1079 |
| 1080 DCHECK(!waiting_for_asynchronus_reporting_step_); |
| 1081 |
| 1082 waiting_for_asynchronus_reporting_step_ = true; |
| 1083 current_fetch_xml_->Start(); |
| 1084 if (current_fetch_proto_.get()) |
| 1085 current_fetch_proto_->Start(); |
| 1086 |
| 1087 HandleIdleSinceLastTransmission(true); |
| 1088 } |
| 1089 |
1083 void MetricsService::PrepareFetchWithStagedLog() { | 1090 void MetricsService::PrepareFetchWithStagedLog() { |
1084 DCHECK(!log_manager_.staged_log_text().empty()); | 1091 DCHECK(!log_manager_.staged_log_text().empty()); |
1085 | 1092 |
1086 // Prepare the XML version. | 1093 // Prepare the XML version. |
1087 DCHECK(!current_fetch_xml_.get()); | 1094 DCHECK(!current_fetch_xml_.get()); |
1088 current_fetch_xml_.reset(content::URLFetcher::Create( | 1095 current_fetch_xml_.reset(content::URLFetcher::Create( |
1089 GURL(server_url_xml_), content::URLFetcher::POST, this)); | 1096 GURL(server_url_xml_), content::URLFetcher::POST, this)); |
1090 current_fetch_xml_->SetRequestContext( | 1097 current_fetch_xml_->SetRequestContext( |
1091 g_browser_process->system_request_context()); | 1098 g_browser_process->system_request_context()); |
1092 current_fetch_xml_->SetUploadData(kMetricsTypeXml, | 1099 current_fetch_xml_->SetUploadData(kMetricsTypeXml, |
(...skipping 558 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1651 if (local_state) { | 1658 if (local_state) { |
1652 const PrefService::Preference* uma_pref = | 1659 const PrefService::Preference* uma_pref = |
1653 local_state->FindPreference(prefs::kMetricsReportingEnabled); | 1660 local_state->FindPreference(prefs::kMetricsReportingEnabled); |
1654 if (uma_pref) { | 1661 if (uma_pref) { |
1655 bool success = uma_pref->GetValue()->GetAsBoolean(&result); | 1662 bool success = uma_pref->GetValue()->GetAsBoolean(&result); |
1656 DCHECK(success); | 1663 DCHECK(success); |
1657 } | 1664 } |
1658 } | 1665 } |
1659 return result; | 1666 return result; |
1660 } | 1667 } |
OLD | NEW |