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 779 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
790 } | 790 } |
791 | 791 |
792 | 792 |
793 //------------------------------------------------------------------------------ | 793 //------------------------------------------------------------------------------ |
794 // Recording control methods | 794 // Recording control methods |
795 | 795 |
796 void MetricsService::StartRecording() { | 796 void MetricsService::StartRecording() { |
797 if (log_manager_.current_log()) | 797 if (log_manager_.current_log()) |
798 return; | 798 return; |
799 | 799 |
800 log_manager_.BeginLoggingWithLog(new MetricsLog(client_id_, session_id_)); | 800 log_manager_.BeginLoggingWithLog(new MetricsLog(client_id_, session_id_), |
| 801 MetricsLogManager::ONGOING_LOG); |
801 if (state_ == INITIALIZED) { | 802 if (state_ == INITIALIZED) { |
802 // We only need to schedule that run once. | 803 // We only need to schedule that run once. |
803 state_ = INIT_TASK_SCHEDULED; | 804 state_ = INIT_TASK_SCHEDULED; |
804 | 805 |
805 // Schedules a task on the file thread for execution of slower | 806 // Schedules a task on the file thread for execution of slower |
806 // initialization steps (such as plugin list generation) necessary | 807 // initialization steps (such as plugin list generation) necessary |
807 // for sending the initial log. This avoids blocking the main UI | 808 // for sending the initial log. This avoids blocking the main UI |
808 // thread. | 809 // thread. |
809 BrowserThread::PostDelayedTask( | 810 BrowserThread::PostDelayedTask( |
810 BrowserThread::FILE, | 811 BrowserThread::FILE, |
(...skipping 24 matching lines...) Expand all Loading... |
835 // Put incremental data (histogram deltas, and realtime stats deltas) at the | 836 // Put incremental data (histogram deltas, and realtime stats deltas) at the |
836 // end of all log transmissions (initial log handles this separately). | 837 // end of all log transmissions (initial log handles this separately). |
837 // RecordIncrementalStabilityElements only exists on the derived | 838 // RecordIncrementalStabilityElements only exists on the derived |
838 // MetricsLog class. | 839 // MetricsLog class. |
839 MetricsLog* current_log = | 840 MetricsLog* current_log = |
840 static_cast<MetricsLog*>(log_manager_.current_log()); | 841 static_cast<MetricsLog*>(log_manager_.current_log()); |
841 DCHECK(current_log); | 842 DCHECK(current_log); |
842 current_log->RecordIncrementalStabilityElements(); | 843 current_log->RecordIncrementalStabilityElements(); |
843 RecordCurrentHistograms(); | 844 RecordCurrentHistograms(); |
844 | 845 |
845 log_manager_.StageCurrentLogForUpload(); | 846 log_manager_.FinishCurrentLog(); |
846 } | 847 } |
847 | 848 |
848 void MetricsService::PushPendingLogsToPersistentStorage() { | 849 void MetricsService::PushPendingLogsToPersistentStorage() { |
849 if (state_ < INITIAL_LOG_READY) | 850 if (state_ < INITIAL_LOG_READY) |
850 return; // We didn't and still don't have time to get plugin list etc. | 851 return; // We didn't and still don't have time to get plugin list etc. |
851 | 852 |
852 if (log_manager_.has_staged_log()) { | 853 if (log_manager_.has_staged_log()) { |
853 if (state_ == INITIAL_LOG_READY) { | 854 // We may race here, and send second copy of initial log later. |
854 // We may race here, and send second copy of initial log later. | 855 if (state_ == INITIAL_LOG_READY) |
855 log_manager_.StoreStagedLogAsUnsent(MetricsLogManager::INITIAL_LOG); | |
856 state_ = SENDING_OLD_LOGS; | 856 state_ = SENDING_OLD_LOGS; |
857 } else { | 857 log_manager_.StoreStagedLogAsUnsent(); |
858 // TODO(jar): Verify correctness in other states, including sending unsent | |
859 // initial logs. | |
860 log_manager_.StoreStagedLogAsUnsent(MetricsLogManager::ONGOING_LOG); | |
861 } | |
862 } | 858 } |
863 DCHECK(!log_manager_.has_staged_log()); | 859 DCHECK(!log_manager_.has_staged_log()); |
864 StopRecording(); | 860 StopRecording(); |
865 log_manager_.StoreStagedLogAsUnsent(MetricsLogManager::ONGOING_LOG); | |
866 StoreUnsentLogs(); | 861 StoreUnsentLogs(); |
867 } | 862 } |
868 | 863 |
869 //------------------------------------------------------------------------------ | 864 //------------------------------------------------------------------------------ |
870 // Transmission of logs methods | 865 // Transmission of logs methods |
871 | 866 |
872 void MetricsService::StartSchedulerIfNecessary() { | 867 void MetricsService::StartSchedulerIfNecessary() { |
873 if (reporting_active() && recording_active()) | 868 if (reporting_active() && recording_active()) |
874 scheduler_->Start(); | 869 scheduler_->Start(); |
875 } | 870 } |
876 | 871 |
877 void MetricsService::StartScheduledUpload() { | 872 void MetricsService::StartScheduledUpload() { |
878 // If reporting has been turned off, the scheduler doesn't need to run. | 873 // If reporting has been turned off, the scheduler doesn't need to run. |
879 if (!reporting_active() || !recording_active()) { | 874 if (!reporting_active() || !recording_active()) { |
880 scheduler_->Stop(); | 875 scheduler_->Stop(); |
881 scheduler_->UploadCancelled(); | 876 scheduler_->UploadCancelled(); |
882 return; | 877 return; |
883 } | 878 } |
884 | 879 |
| 880 StartFinalLogInfoCollection(); |
| 881 } |
| 882 |
| 883 void MetricsService::StartFinalLogInfoCollection() { |
| 884 // Begin the multi-step process of collecting memory usage histograms: |
| 885 // First spawn a task to collect the memory details; when that task is |
| 886 // finished, it will call OnMemoryDetailCollectionDone. That will in turn |
| 887 // call HistogramSynchronization to collect histograms from all renderers and |
| 888 // then call OnHistogramSynchronizationDone to continue processing. |
885 DCHECK(!waiting_for_asynchronus_reporting_step_); | 889 DCHECK(!waiting_for_asynchronus_reporting_step_); |
886 waiting_for_asynchronus_reporting_step_ = true; | 890 waiting_for_asynchronus_reporting_step_ = true; |
887 | 891 |
888 base::Closure callback = | 892 base::Closure callback = |
889 base::Bind(&MetricsService::OnMemoryDetailCollectionDone, | 893 base::Bind(&MetricsService::OnMemoryDetailCollectionDone, |
890 log_sender_factory_.GetWeakPtr()); | 894 log_sender_factory_.GetWeakPtr()); |
891 | 895 |
892 scoped_refptr<MetricsMemoryDetails> details( | 896 scoped_refptr<MetricsMemoryDetails> details( |
893 new MetricsMemoryDetails(callback)); | 897 new MetricsMemoryDetails(callback)); |
894 details->StartFetch(); | 898 details->StartFetch(); |
895 | 899 |
896 // Collect WebCore cache information to put into a histogram. | 900 // Collect WebCore cache information to put into a histogram. |
897 for (content::RenderProcessHost::iterator i( | 901 for (content::RenderProcessHost::iterator i( |
898 content::RenderProcessHost::AllHostsIterator()); | 902 content::RenderProcessHost::AllHostsIterator()); |
899 !i.IsAtEnd(); i.Advance()) | 903 !i.IsAtEnd(); i.Advance()) |
900 i.GetCurrentValue()->Send(new ChromeViewMsg_GetCacheResourceStats()); | 904 i.GetCurrentValue()->Send(new ChromeViewMsg_GetCacheResourceStats()); |
901 } | 905 } |
902 | 906 |
903 void MetricsService::OnMemoryDetailCollectionDone() { | 907 void MetricsService::OnMemoryDetailCollectionDone() { |
904 DCHECK(IsSingleThreaded()); | 908 DCHECK(IsSingleThreaded()); |
905 // This function should only be called as the callback from an ansynchronous | 909 // This function should only be called as the callback from an ansynchronous |
906 // step. | 910 // step. |
907 DCHECK(waiting_for_asynchronus_reporting_step_); | 911 DCHECK(waiting_for_asynchronus_reporting_step_); |
908 | 912 |
909 // Right before the UMA transmission gets started, there's one more thing we'd | |
910 // like to record: the histogram of memory usage, so we spawn a task to | |
911 // collect the memory details and when that task is finished, it will call | |
912 // OnMemoryDetailCollectionDone, which will call HistogramSynchronization to | |
913 // collect histograms from all renderers and then we will call | |
914 // OnHistogramSynchronizationDone to continue processing. | |
915 | |
916 // Create a callback_task for OnHistogramSynchronizationDone. | 913 // Create a callback_task for OnHistogramSynchronizationDone. |
917 base::Closure callback = base::Bind( | 914 base::Closure callback = base::Bind( |
918 &MetricsService::OnHistogramSynchronizationDone, | 915 &MetricsService::OnHistogramSynchronizationDone, |
919 log_sender_factory_.GetWeakPtr()); | 916 log_sender_factory_.GetWeakPtr()); |
920 | 917 |
921 base::StatisticsRecorder::CollectHistogramStats("Browser"); | 918 base::StatisticsRecorder::CollectHistogramStats("Browser"); |
922 | 919 |
923 // Set up the callback to task to call after we receive histograms from all | 920 // Set up the callback to task to call after we receive histograms from all |
924 // renderer processes. Wait time specifies how long to wait before absolutely | 921 // renderer processes. Wait time specifies how long to wait before absolutely |
925 // calling us back on the task. | 922 // calling us back on the task. |
926 HistogramSynchronizer::FetchRendererHistogramsAsynchronously( | 923 HistogramSynchronizer::FetchRendererHistogramsAsynchronously( |
927 MessageLoop::current(), callback, | 924 MessageLoop::current(), callback, |
928 kMaxHistogramGatheringWaitDuration); | 925 kMaxHistogramGatheringWaitDuration); |
929 } | 926 } |
930 | 927 |
931 void MetricsService::OnHistogramSynchronizationDone() { | 928 void MetricsService::OnHistogramSynchronizationDone() { |
932 DCHECK(IsSingleThreaded()); | 929 DCHECK(IsSingleThreaded()); |
| 930 // This function should only be called as the callback from an ansynchronous |
| 931 // step. |
| 932 DCHECK(waiting_for_asynchronus_reporting_step_); |
933 | 933 |
| 934 waiting_for_asynchronus_reporting_step_ = false; |
| 935 OnFinalLogInfoCollectionDone(); |
| 936 } |
| 937 |
| 938 void MetricsService::OnFinalLogInfoCollectionDone() { |
934 // If somehow there is a fetch in progress, we return and hope things work | 939 // If somehow there is a fetch in progress, we return and hope things work |
935 // out. The scheduler isn't informed since if this happens, the scheduler | 940 // out. The scheduler isn't informed since if this happens, the scheduler |
936 // will get a response from the upload. | 941 // will get a response from the upload. |
937 DCHECK(!current_fetch_.get()); | 942 DCHECK(!current_fetch_.get()); |
938 if (current_fetch_.get()) | 943 if (current_fetch_.get()) |
939 return; | 944 return; |
940 | 945 |
941 // This function should only be called as the callback from an ansynchronous | |
942 // step. | |
943 DCHECK(waiting_for_asynchronus_reporting_step_); | |
944 waiting_for_asynchronus_reporting_step_ = false; | |
945 | |
946 // If we're getting no notifications, then the log won't have much in it, and | 946 // If we're getting no notifications, then the log won't have much in it, and |
947 // it's possible the computer is about to go to sleep, so don't upload and | 947 // it's possible the computer is about to go to sleep, so don't upload and |
948 // stop the scheduler. | 948 // stop the scheduler. |
949 // Similarly, if logs should no longer be uploaded, stop here. | 949 // Similarly, if logs should no longer be uploaded, stop here. |
950 if (idle_since_last_transmission_ || | 950 if (idle_since_last_transmission_ || |
951 !recording_active() || !reporting_active()) { | 951 !recording_active() || !reporting_active()) { |
952 scheduler_->Stop(); | 952 scheduler_->Stop(); |
953 scheduler_->UploadCancelled(); | 953 scheduler_->UploadCancelled(); |
954 return; | 954 return; |
955 } | 955 } |
956 | 956 |
957 MakeStagedLog(); | 957 MakeStagedLog(); |
958 | 958 |
959 // MakeStagedLog should have prepared log text; if it didn't, skip this | 959 // MakeStagedLog should have prepared log text; if it didn't, skip this |
960 // upload and hope things work out next time. | 960 // upload and hope things work out next time. |
961 if (log_manager_.staged_log_text().empty()) { | 961 if (log_manager_.staged_log_text().empty()) { |
962 scheduler_->UploadCancelled(); | 962 scheduler_->UploadCancelled(); |
963 return; | 963 return; |
964 } | 964 } |
965 | 965 |
966 PrepareFetchWithStagedLog(); | 966 SendStagedLog(); |
967 | |
968 if (!current_fetch_.get()) { | |
969 // Compression failed, and log discarded :-/. | |
970 log_manager_.DiscardStagedLog(); | |
971 scheduler_->UploadCancelled(); | |
972 // TODO(jar): If compression failed, we should have created a tiny log and | |
973 // compressed that, so that we can signal that we're losing logs. | |
974 return; | |
975 } | |
976 | |
977 DCHECK(!waiting_for_asynchronus_reporting_step_); | |
978 | |
979 waiting_for_asynchronus_reporting_step_ = true; | |
980 current_fetch_->Start(); | |
981 | |
982 HandleIdleSinceLastTransmission(true); | |
983 } | 967 } |
984 | 968 |
985 | |
986 void MetricsService::MakeStagedLog() { | 969 void MetricsService::MakeStagedLog() { |
987 if (log_manager_.has_staged_log()) | 970 if (log_manager_.has_staged_log()) |
988 return; | 971 return; |
989 | 972 |
990 switch (state_) { | 973 switch (state_) { |
991 case INITIALIZED: | 974 case INITIALIZED: |
992 case INIT_TASK_SCHEDULED: // We should be further along by now. | 975 case INIT_TASK_SCHEDULED: // We should be further along by now. |
993 DCHECK(false); | 976 DCHECK(false); |
994 return; | 977 return; |
995 | 978 |
996 case INIT_TASK_DONE: | 979 case INIT_TASK_DONE: |
997 // We need to wait for the initial log to be ready before sending | 980 // We need to wait for the initial log to be ready before sending |
998 // anything, because the server will tell us whether it wants to hear | 981 // anything, because the server will tell us whether it wants to hear |
999 // from us. | 982 // from us. |
1000 PrepareInitialLog(); | 983 PrepareInitialLog(); |
1001 DCHECK(state_ == INIT_TASK_DONE); | 984 DCHECK(state_ == INIT_TASK_DONE); |
1002 log_manager_.LoadPersistedUnsentLogs(); | 985 log_manager_.LoadPersistedUnsentLogs(); |
1003 state_ = INITIAL_LOG_READY; | 986 state_ = INITIAL_LOG_READY; |
1004 break; | 987 break; |
1005 | 988 |
1006 case SENDING_OLD_LOGS: | 989 case SENDING_OLD_LOGS: |
1007 if (log_manager_.has_unsent_logs()) { | 990 if (log_manager_.has_unsent_logs()) { |
1008 log_manager_.StageNextStoredLogForUpload(); | 991 log_manager_.StageNextLogForUpload(); |
1009 break; | 992 break; |
1010 } | 993 } |
1011 state_ = SENDING_CURRENT_LOGS; | 994 state_ = SENDING_CURRENT_LOGS; |
1012 // Fall through. | 995 // Fall through. |
1013 | 996 |
1014 case SENDING_CURRENT_LOGS: | 997 case SENDING_CURRENT_LOGS: |
1015 StopRecording(); | 998 StopRecording(); |
1016 StartRecording(); | 999 StartRecording(); |
| 1000 log_manager_.StageNextLogForUpload(); |
1017 break; | 1001 break; |
1018 | 1002 |
1019 default: | 1003 default: |
1020 NOTREACHED(); | 1004 NOTREACHED(); |
1021 return; | 1005 return; |
1022 } | 1006 } |
1023 | 1007 |
1024 DCHECK(log_manager_.has_staged_log()); | 1008 DCHECK(log_manager_.has_staged_log()); |
1025 } | 1009 } |
1026 | 1010 |
1027 void MetricsService::PrepareInitialLog() { | 1011 void MetricsService::PrepareInitialLog() { |
1028 DCHECK(state_ == INIT_TASK_DONE); | 1012 DCHECK(state_ == INIT_TASK_DONE); |
1029 | 1013 |
1030 MetricsLog* log = new MetricsLog(client_id_, session_id_); | 1014 MetricsLog* log = new MetricsLog(client_id_, session_id_); |
1031 log->set_hardware_class(hardware_class_); // Adds to initial log. | 1015 log->set_hardware_class(hardware_class_); // Adds to initial log. |
1032 log->RecordEnvironment(plugins_, profile_dictionary_.get()); | 1016 log->RecordEnvironment(plugins_, profile_dictionary_.get()); |
1033 | 1017 |
1034 // Histograms only get written to the current log, so make the new log current | 1018 // Histograms only get written to the current log, so make the new log current |
1035 // before writing them. | 1019 // before writing them. |
1036 log_manager_.PauseCurrentLog(); | 1020 log_manager_.PauseCurrentLog(); |
1037 log_manager_.BeginLoggingWithLog(log); | 1021 log_manager_.BeginLoggingWithLog(log, MetricsLogManager::INITIAL_LOG); |
1038 RecordCurrentHistograms(); | 1022 RecordCurrentHistograms(); |
| 1023 log_manager_.FinishCurrentLog(); |
| 1024 log_manager_.ResumePausedLog(); |
1039 | 1025 |
1040 DCHECK(!log_manager_.has_staged_log()); | 1026 DCHECK(!log_manager_.has_staged_log()); |
1041 log_manager_.StageCurrentLogForUpload(); | 1027 log_manager_.StageNextLogForUpload(); |
1042 log_manager_.ResumePausedLog(); | |
1043 } | 1028 } |
1044 | 1029 |
1045 void MetricsService::StoreUnsentLogs() { | 1030 void MetricsService::StoreUnsentLogs() { |
1046 if (state_ < INITIAL_LOG_READY) | 1031 if (state_ < INITIAL_LOG_READY) |
1047 return; // We never Recalled the prior unsent logs. | 1032 return; // We never Recalled the prior unsent logs. |
1048 | 1033 |
1049 log_manager_.PersistUnsentLogs(); | 1034 log_manager_.PersistUnsentLogs(); |
1050 } | 1035 } |
1051 | 1036 |
| 1037 void MetricsService::SendStagedLog() { |
| 1038 DCHECK(log_manager_.has_staged_log()); |
| 1039 |
| 1040 PrepareFetchWithStagedLog(); |
| 1041 |
| 1042 if (!current_fetch_.get()) { |
| 1043 // Compression failed, and log discarded :-/. |
| 1044 log_manager_.DiscardStagedLog(); |
| 1045 scheduler_->UploadCancelled(); |
| 1046 // TODO(jar): If compression failed, we should have created a tiny log and |
| 1047 // compressed that, so that we can signal that we're losing logs. |
| 1048 return; |
| 1049 } |
| 1050 |
| 1051 DCHECK(!waiting_for_asynchronus_reporting_step_); |
| 1052 |
| 1053 waiting_for_asynchronus_reporting_step_ = true; |
| 1054 current_fetch_->Start(); |
| 1055 |
| 1056 HandleIdleSinceLastTransmission(true); |
| 1057 } |
| 1058 |
1052 void MetricsService::PrepareFetchWithStagedLog() { | 1059 void MetricsService::PrepareFetchWithStagedLog() { |
1053 DCHECK(!log_manager_.staged_log_text().empty()); | 1060 DCHECK(!log_manager_.staged_log_text().empty()); |
1054 DCHECK(!current_fetch_.get()); | 1061 DCHECK(!current_fetch_.get()); |
1055 | 1062 |
1056 current_fetch_.reset(content::URLFetcher::Create( | 1063 current_fetch_.reset(content::URLFetcher::Create( |
1057 GURL(WideToUTF16(server_url_)), content::URLFetcher::POST, this)); | 1064 GURL(WideToUTF16(server_url_)), content::URLFetcher::POST, this)); |
1058 current_fetch_->SetRequestContext( | 1065 current_fetch_->SetRequestContext( |
1059 g_browser_process->system_request_context()); | 1066 g_browser_process->system_request_context()); |
1060 current_fetch_->SetUploadData(kMetricsType, log_manager_.staged_log_text()); | 1067 current_fetch_->SetUploadData(kMetricsType, log_manager_.staged_log_text()); |
1061 } | 1068 } |
(...skipping 494 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1556 if (local_state) { | 1563 if (local_state) { |
1557 const PrefService::Preference* uma_pref = | 1564 const PrefService::Preference* uma_pref = |
1558 local_state->FindPreference(prefs::kMetricsReportingEnabled); | 1565 local_state->FindPreference(prefs::kMetricsReportingEnabled); |
1559 if (uma_pref) { | 1566 if (uma_pref) { |
1560 bool success = uma_pref->GetValue()->GetAsBoolean(&result); | 1567 bool success = uma_pref->GetValue()->GetAsBoolean(&result); |
1561 DCHECK(success); | 1568 DCHECK(success); |
1562 } | 1569 } |
1563 } | 1570 } |
1564 return result; | 1571 return result; |
1565 } | 1572 } |
OLD | NEW |