upload_service.cc revision 6b8629a6490d01196368ae1ed5bc6967c6f127eb
1/* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "uploader/upload_service.h" 18 19#include <sysexits.h> 20 21#include <string> 22 23#include <base/bind.h> 24#include <base/files/file_util.h> 25#include <base/logging.h> 26#include <base/memory/scoped_vector.h> 27#include <base/message_loop/message_loop.h> 28#include <base/metrics/histogram.h> 29#include <base/metrics/histogram_base.h> 30#include <base/metrics/histogram_snapshot_manager.h> 31#include <base/metrics/sparse_histogram.h> 32#include <base/metrics/statistics_recorder.h> 33#include <base/sha1.h> 34 35#include "constants.h" 36#include "uploader/metrics_log.h" 37#include "uploader/sender_http.h" 38#include "uploader/system_profile_setter.h" 39 40const int UploadService::kMaxFailedUpload = 10; 41 42UploadService::UploadService(const std::string& server, 43 const base::TimeDelta& upload_interval, 44 const base::FilePath& private_metrics_directory, 45 const base::FilePath& shared_metrics_directory, 46 const std::shared_ptr<CrashCounters> counters) 47 : histogram_snapshot_manager_(this), 48 sender_(new HttpSender(server)), 49 failed_upload_count_(metrics::kFailedUploadCountName, 50 private_metrics_directory), 51 counters_(counters), 52 upload_interval_(upload_interval) { 53 staged_log_path_ = private_metrics_directory.Append(metrics::kStagedLogName); 54 consent_file_ = shared_metrics_directory.Append(metrics::kConsentFileName); 55} 56 57int UploadService::OnInit() { 58 system_profile_setter_.reset(new SystemProfileCache()); 59 60 base::MessageLoop::current()->PostDelayedTask(FROM_HERE, 61 base::Bind(&UploadService::UploadEventCallback, 62 base::Unretained(this), 63 upload_interval_), 64 upload_interval_); 65 return EX_OK; 66} 67 68void UploadService::InitForTest(SystemProfileSetter* setter) { 69 system_profile_setter_.reset(setter); 70} 71 72void UploadService::StartNewLog() { 73 CHECK(!HasStagedLog()) << "the staged log should be discarded before " 74 << "starting a new metrics log"; 75 MetricsLog* log = new MetricsLog(); 76 current_log_.reset(log); 77} 78 79void UploadService::UploadEventCallback(const base::TimeDelta& interval) { 80 UploadEvent(); 81 82 base::MessageLoop::current()->PostDelayedTask(FROM_HERE, 83 base::Bind(&UploadService::UploadEventCallback, 84 base::Unretained(this), 85 interval), 86 interval); 87} 88 89void UploadService::UploadEvent() { 90 // If the system shutdown or crashed while uploading a report, we may not have 91 // deleted an old log. 92 RemoveFailedLog(); 93 94 if (HasStagedLog()) { 95 // Previous upload failed, retry sending the logs. 96 SendStagedLog(); 97 return; 98 } 99 100 // Previous upload successful, stage another log. 101 GatherHistograms(); 102 StageCurrentLog(); 103 104 // If a log is available for upload, upload it. 105 if (HasStagedLog()) { 106 SendStagedLog(); 107 } 108} 109 110void UploadService::SendStagedLog() { 111 // If metrics are not enabled, discard the log and exit. 112 if (!AreMetricsEnabled()) { 113 LOG(INFO) << "Metrics disabled. Don't upload metrics samples."; 114 base::DeleteFile(staged_log_path_, false); 115 return; 116 } 117 118 std::string staged_log; 119 CHECK(base::ReadFileToString(staged_log_path_, &staged_log)); 120 121 // Increase the failed count in case the daemon crashes while sending the log. 122 failed_upload_count_.Add(1); 123 124 if (!sender_->Send(staged_log, base::SHA1HashString(staged_log))) { 125 LOG(WARNING) << "log failed to upload"; 126 } else { 127 VLOG(1) << "uploaded " << staged_log.length() << " bytes"; 128 base::DeleteFile(staged_log_path_, false); 129 } 130 131 RemoveFailedLog(); 132} 133 134void UploadService::Reset() { 135 base::DeleteFile(staged_log_path_, false); 136 current_log_.reset(); 137 failed_upload_count_.Set(0); 138} 139 140void UploadService::GatherHistograms() { 141 base::StatisticsRecorder::Histograms histograms; 142 base::StatisticsRecorder::GetHistograms(&histograms); 143 144 histogram_snapshot_manager_.PrepareDeltas( 145 base::Histogram::kNoFlags, base::Histogram::kUmaTargetedHistogramFlag); 146 147 // Gather and reset the crash counters, shared with the binder threads. 148 unsigned int kernel_crashes = counters_->GetAndResetKernelCrashCount(); 149 unsigned int unclean_shutdowns = counters_->GetAndResetUncleanShutdownCount(); 150 unsigned int user_crashes = counters_->GetAndResetUserCrashCount(); 151 152 // Only create a log if the counters have changed. 153 if (kernel_crashes > 0 || unclean_shutdowns > 0 || user_crashes > 0) { 154 GetOrCreateCurrentLog()->IncrementKernelCrashCount(kernel_crashes); 155 GetOrCreateCurrentLog()->IncrementUncleanShutdownCount(unclean_shutdowns); 156 GetOrCreateCurrentLog()->IncrementUserCrashCount(user_crashes); 157 } 158} 159 160void UploadService::RecordDelta(const base::HistogramBase& histogram, 161 const base::HistogramSamples& snapshot) { 162 GetOrCreateCurrentLog()->RecordHistogramDelta(histogram.histogram_name(), 163 snapshot); 164} 165 166void UploadService::StageCurrentLog() { 167 // If we haven't logged anything since the last upload, don't upload an empty 168 // report. 169 if (!current_log_) 170 return; 171 172 scoped_ptr<MetricsLog> staged_log; 173 staged_log.swap(current_log_); 174 staged_log->CloseLog(); 175 if (!staged_log->PopulateSystemProfile(system_profile_setter_.get())) { 176 LOG(WARNING) << "Error while adding metadata to the log. Discarding the " 177 << "log."; 178 return; 179 } 180 std::string encoded_log; 181 staged_log->GetEncodedLog(&encoded_log); 182 183 failed_upload_count_.Set(0); 184 if (static_cast<int>(encoded_log.size()) != base::WriteFile( 185 staged_log_path_, encoded_log.data(), encoded_log.size())) { 186 LOG(ERROR) << "failed to persist to " << staged_log_path_.value(); 187 } 188} 189 190MetricsLog* UploadService::GetOrCreateCurrentLog() { 191 if (!current_log_) { 192 StartNewLog(); 193 } 194 return current_log_.get(); 195} 196 197bool UploadService::HasStagedLog() { 198 return base::PathExists(staged_log_path_); 199} 200 201void UploadService::RemoveFailedLog() { 202 if (failed_upload_count_.Get() > kMaxFailedUpload) { 203 LOG(INFO) << "log failed more than " << kMaxFailedUpload << " times."; 204 CHECK(base::DeleteFile(staged_log_path_, false)) 205 << "failed to delete staged log at " << staged_log_path_.value(); 206 failed_upload_count_.Set(0); 207 } 208} 209 210bool UploadService::AreMetricsEnabled() { 211 return base::PathExists(consent_file_); 212} 213