blob: 333a7e6aad6b429ed3e1b8ee8f22ce2c63ba8983 [file] [log] [blame]
Bertrand SIMONNET52e5b992015-08-10 15:18:00 -07001/*
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 */
Bertrand SIMONNET46b49da2014-06-25 14:38:07 -070016
Bertrand SIMONNET4b915ae2015-07-28 15:38:14 -070017#include "uploader/upload_service.h"
Bertrand SIMONNET46b49da2014-06-25 14:38:07 -070018
Bertrand SIMONNET608e4282015-11-12 17:52:17 -080019#include <sysexits.h>
20
Bertrand SIMONNET6c9fbb92015-12-21 14:56:40 -080021#include <memory>
Bertrand SIMONNET46b49da2014-06-25 14:38:07 -070022#include <string>
23
Steve Fungae4bdc42015-01-26 17:13:24 -080024#include <base/bind.h>
Bertrand SIMONNET1df10c42015-09-09 10:39:51 -070025#include <base/files/file_util.h>
Alex Vakulenkoec991df2014-09-04 16:16:28 -070026#include <base/logging.h>
27#include <base/memory/scoped_vector.h>
Steve Fungae4bdc42015-01-26 17:13:24 -080028#include <base/message_loop/message_loop.h>
Alex Vakulenkoec991df2014-09-04 16:16:28 -070029#include <base/metrics/histogram.h>
30#include <base/metrics/histogram_base.h>
31#include <base/metrics/histogram_snapshot_manager.h>
32#include <base/metrics/sparse_histogram.h>
33#include <base/metrics/statistics_recorder.h>
34#include <base/sha1.h>
Alex Vakulenkoec991df2014-09-04 16:16:28 -070035
Bertrand SIMONNET2765d0a2015-09-09 10:38:20 -070036#include "constants.h"
Bertrand SIMONNET4b915ae2015-07-28 15:38:14 -070037#include "uploader/metrics_log.h"
38#include "uploader/sender_http.h"
Bertrand SIMONNET52e1d552015-08-04 15:06:21 -070039#include "uploader/system_profile_setter.h"
Bertrand SIMONNET46b49da2014-06-25 14:38:07 -070040
Bertrand SIMONNET46b49da2014-06-25 14:38:07 -070041const int UploadService::kMaxFailedUpload = 10;
42
Bertrand SIMONNET608e4282015-11-12 17:52:17 -080043UploadService::UploadService(const std::string& server,
44 const base::TimeDelta& upload_interval,
Bertrand SIMONNET05865042015-12-15 12:33:01 -080045 const base::TimeDelta& disk_persistence_interval,
Bertrand SIMONNET9d3a4ae2015-11-25 13:49:12 -080046 const base::FilePath& private_metrics_directory,
Bertrand SIMONNETb6c77af2015-12-08 17:46:00 -080047 const base::FilePath& shared_metrics_directory)
48 : brillo::Daemon(),
49 histogram_snapshot_manager_(this),
Steve Fungae4bdc42015-01-26 17:13:24 -080050 sender_(new HttpSender(server)),
Bertrand SIMONNET9d3a4ae2015-11-25 13:49:12 -080051 failed_upload_count_(metrics::kFailedUploadCountName,
52 private_metrics_directory),
Bertrand SIMONNETb6c77af2015-12-08 17:46:00 -080053 counters_(new CrashCounters),
54 upload_interval_(upload_interval),
Bertrand SIMONNET05865042015-12-15 12:33:01 -080055 disk_persistence_interval_(disk_persistence_interval),
Bertrand SIMONNETb6c77af2015-12-08 17:46:00 -080056 metricsd_service_runner_(counters_) {
Bertrand SIMONNET9d3a4ae2015-11-25 13:49:12 -080057 staged_log_path_ = private_metrics_directory.Append(metrics::kStagedLogName);
Bertrand SIMONNET05865042015-12-15 12:33:01 -080058 saved_log_path_ = private_metrics_directory.Append(metrics::kSavedLogName);
Bertrand SIMONNET9d3a4ae2015-11-25 13:49:12 -080059 consent_file_ = shared_metrics_directory.Append(metrics::kConsentFileName);
Bertrand SIMONNET608e4282015-11-12 17:52:17 -080060}
Steve Fungae4bdc42015-01-26 17:13:24 -080061
Bertrand SIMONNET05865042015-12-15 12:33:01 -080062void UploadService::LoadSavedLog() {
63 if (base::PathExists(saved_log_path_)) {
64 GetOrCreateCurrentLog()->LoadFromFile(saved_log_path_);
65 }
66}
67
Bertrand SIMONNET608e4282015-11-12 17:52:17 -080068int UploadService::OnInit() {
Bertrand SIMONNETb6c77af2015-12-08 17:46:00 -080069 brillo::Daemon::OnInit();
70
71 base::StatisticsRecorder::Initialize();
72 metricsd_service_runner_.Start();
73
Bertrand SIMONNET608e4282015-11-12 17:52:17 -080074 system_profile_setter_.reset(new SystemProfileCache());
75
Bertrand SIMONNET05865042015-12-15 12:33:01 -080076 base::MessageLoop::current()->PostDelayedTask(
77 FROM_HERE,
78 base::Bind(&UploadService::UploadEventCallback, base::Unretained(this)),
Bertrand SIMONNET608e4282015-11-12 17:52:17 -080079 upload_interval_);
Bertrand SIMONNETb6c77af2015-12-08 17:46:00 -080080
Bertrand SIMONNET05865042015-12-15 12:33:01 -080081 base::MessageLoop::current()->PostDelayedTask(
82 FROM_HERE,
83 base::Bind(&UploadService::PersistEventCallback, base::Unretained(this)),
84 disk_persistence_interval_);
85
86 LoadSavedLog();
87
Bertrand SIMONNET608e4282015-11-12 17:52:17 -080088 return EX_OK;
89}
90
Bertrand SIMONNETb6c77af2015-12-08 17:46:00 -080091void UploadService::OnShutdown(int* exit_code) {
92 metricsd_service_runner_.Stop();
Bertrand SIMONNETd6862312016-01-19 14:04:25 -080093 PersistToDisk();
Bertrand SIMONNETb6c77af2015-12-08 17:46:00 -080094}
95
Bertrand SIMONNET608e4282015-11-12 17:52:17 -080096void UploadService::InitForTest(SystemProfileSetter* setter) {
Bertrand SIMONNET05865042015-12-15 12:33:01 -080097 LoadSavedLog();
Bertrand SIMONNET608e4282015-11-12 17:52:17 -080098 system_profile_setter_.reset(setter);
Bertrand SIMONNET46b49da2014-06-25 14:38:07 -070099}
100
101void UploadService::StartNewLog() {
Bertrand SIMONNET05865042015-12-15 12:33:01 -0800102 current_log_.reset(new MetricsLog());
Bertrand SIMONNET46b49da2014-06-25 14:38:07 -0700103}
104
Bertrand SIMONNET05865042015-12-15 12:33:01 -0800105void UploadService::UploadEventCallback() {
Steve Fungae4bdc42015-01-26 17:13:24 -0800106 UploadEvent();
107
Bertrand SIMONNET05865042015-12-15 12:33:01 -0800108 base::MessageLoop::current()->PostDelayedTask(
109 FROM_HERE,
110 base::Bind(&UploadService::UploadEventCallback, base::Unretained(this)),
111 upload_interval_);
112}
113
114void UploadService::PersistEventCallback() {
115 PersistToDisk();
116
117 base::MessageLoop::current()->PostDelayedTask(
118 FROM_HERE,
119 base::Bind(&UploadService::PersistEventCallback, base::Unretained(this)),
120 disk_persistence_interval_);
121}
122
123void UploadService::PersistToDisk() {
124 GatherHistograms();
125 if (current_log_) {
126 current_log_->SaveToFile(saved_log_path_);
127 }
Bertrand SIMONNET46b49da2014-06-25 14:38:07 -0700128}
129
130void UploadService::UploadEvent() {
Bertrand SIMONNET1df10c42015-09-09 10:39:51 -0700131 // If the system shutdown or crashed while uploading a report, we may not have
132 // deleted an old log.
133 RemoveFailedLog();
134
135 if (HasStagedLog()) {
Bertrand SIMONNET46b49da2014-06-25 14:38:07 -0700136 // Previous upload failed, retry sending the logs.
137 SendStagedLog();
138 return;
139 }
140
Bertrand SIMONNET6b8629a2015-11-18 13:46:33 -0800141 // Previous upload successful, stage another log.
Bertrand SIMONNET46b49da2014-06-25 14:38:07 -0700142 GatherHistograms();
Bertrand SIMONNET46b49da2014-06-25 14:38:07 -0700143 StageCurrentLog();
Bertrand SIMONNET1f146552015-08-19 18:13:02 -0700144
145 // If a log is available for upload, upload it.
Bertrand SIMONNET1df10c42015-09-09 10:39:51 -0700146 if (HasStagedLog()) {
Bertrand SIMONNET1f146552015-08-19 18:13:02 -0700147 SendStagedLog();
148 }
Bertrand SIMONNET46b49da2014-06-25 14:38:07 -0700149}
150
151void UploadService::SendStagedLog() {
Bertrand SIMONNETe4fa61e2015-02-18 09:38:55 -0800152 // If metrics are not enabled, discard the log and exit.
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800153 if (!AreMetricsEnabled()) {
Bertrand SIMONNETe4fa61e2015-02-18 09:38:55 -0800154 LOG(INFO) << "Metrics disabled. Don't upload metrics samples.";
Bertrand SIMONNET1df10c42015-09-09 10:39:51 -0700155 base::DeleteFile(staged_log_path_, false);
Bertrand SIMONNETe4fa61e2015-02-18 09:38:55 -0800156 return;
157 }
158
Bertrand SIMONNET1df10c42015-09-09 10:39:51 -0700159 std::string staged_log;
160 CHECK(base::ReadFileToString(staged_log_path_, &staged_log));
161
162 // Increase the failed count in case the daemon crashes while sending the log.
163 failed_upload_count_.Add(1);
164
165 if (!sender_->Send(staged_log, base::SHA1HashString(staged_log))) {
166 LOG(WARNING) << "log failed to upload";
Nathan Bullock0be0f732014-09-11 10:29:17 -0400167 } else {
Bertrand SIMONNET1df10c42015-09-09 10:39:51 -0700168 VLOG(1) << "uploaded " << staged_log.length() << " bytes";
169 base::DeleteFile(staged_log_path_, false);
Bertrand SIMONNET46b49da2014-06-25 14:38:07 -0700170 }
Bertrand SIMONNET1df10c42015-09-09 10:39:51 -0700171
172 RemoveFailedLog();
Bertrand SIMONNET46b49da2014-06-25 14:38:07 -0700173}
174
175void UploadService::Reset() {
Bertrand SIMONNET1df10c42015-09-09 10:39:51 -0700176 base::DeleteFile(staged_log_path_, false);
Bertrand SIMONNET46b49da2014-06-25 14:38:07 -0700177 current_log_.reset();
Bertrand SIMONNET1df10c42015-09-09 10:39:51 -0700178 failed_upload_count_.Set(0);
Bertrand SIMONNET46b49da2014-06-25 14:38:07 -0700179}
180
Bertrand SIMONNET46b49da2014-06-25 14:38:07 -0700181void UploadService::GatherHistograms() {
182 base::StatisticsRecorder::Histograms histograms;
183 base::StatisticsRecorder::GetHistograms(&histograms);
184
185 histogram_snapshot_manager_.PrepareDeltas(
Alex Vakulenko3d979292016-03-17 14:29:26 -0700186 histograms.begin(), histograms.end(),
Bertrand SIMONNET46b49da2014-06-25 14:38:07 -0700187 base::Histogram::kNoFlags, base::Histogram::kUmaTargetedHistogramFlag);
Bertrand SIMONNET6b8629a2015-11-18 13:46:33 -0800188
189 // Gather and reset the crash counters, shared with the binder threads.
190 unsigned int kernel_crashes = counters_->GetAndResetKernelCrashCount();
191 unsigned int unclean_shutdowns = counters_->GetAndResetUncleanShutdownCount();
192 unsigned int user_crashes = counters_->GetAndResetUserCrashCount();
193
194 // Only create a log if the counters have changed.
195 if (kernel_crashes > 0 || unclean_shutdowns > 0 || user_crashes > 0) {
196 GetOrCreateCurrentLog()->IncrementKernelCrashCount(kernel_crashes);
197 GetOrCreateCurrentLog()->IncrementUncleanShutdownCount(unclean_shutdowns);
198 GetOrCreateCurrentLog()->IncrementUserCrashCount(user_crashes);
199 }
Bertrand SIMONNET46b49da2014-06-25 14:38:07 -0700200}
201
202void UploadService::RecordDelta(const base::HistogramBase& histogram,
203 const base::HistogramSamples& snapshot) {
204 GetOrCreateCurrentLog()->RecordHistogramDelta(histogram.histogram_name(),
205 snapshot);
206}
207
208void UploadService::StageCurrentLog() {
Bertrand SIMONNET1df10c42015-09-09 10:39:51 -0700209 // If we haven't logged anything since the last upload, don't upload an empty
210 // report.
211 if (!current_log_)
212 return;
Bertrand SIMONNET46b49da2014-06-25 14:38:07 -0700213
Bertrand SIMONNET6c9fbb92015-12-21 14:56:40 -0800214 std::unique_ptr<MetricsLog> staged_log;
Bertrand SIMONNET1df10c42015-09-09 10:39:51 -0700215 staged_log.swap(current_log_);
216 staged_log->CloseLog();
217 if (!staged_log->PopulateSystemProfile(system_profile_setter_.get())) {
Bertrand SIMONNET1f146552015-08-19 18:13:02 -0700218 LOG(WARNING) << "Error while adding metadata to the log. Discarding the "
219 << "log.";
Bertrand SIMONNET1df10c42015-09-09 10:39:51 -0700220 return;
Bertrand SIMONNET1f146552015-08-19 18:13:02 -0700221 }
Bertrand SIMONNET05865042015-12-15 12:33:01 -0800222
223 if (!base::DeleteFile(saved_log_path_, false)) {
224 // There is a chance that we will upload the same metrics twice but, if we
225 // are lucky, the backup should be overridden before that. In doubt, try not
226 // to lose any metrics.
227 LOG(ERROR) << "failed to delete the last backup of the current log.";
228 }
Bertrand SIMONNET1df10c42015-09-09 10:39:51 -0700229
230 failed_upload_count_.Set(0);
Bertrand SIMONNET05865042015-12-15 12:33:01 -0800231 staged_log->SaveToFile(staged_log_path_);
Bertrand SIMONNET46b49da2014-06-25 14:38:07 -0700232}
233
234MetricsLog* UploadService::GetOrCreateCurrentLog() {
235 if (!current_log_) {
236 StartNewLog();
237 }
238 return current_log_.get();
239}
Bertrand SIMONNET1df10c42015-09-09 10:39:51 -0700240
241bool UploadService::HasStagedLog() {
242 return base::PathExists(staged_log_path_);
243}
244
245void UploadService::RemoveFailedLog() {
246 if (failed_upload_count_.Get() > kMaxFailedUpload) {
247 LOG(INFO) << "log failed more than " << kMaxFailedUpload << " times.";
248 CHECK(base::DeleteFile(staged_log_path_, false))
249 << "failed to delete staged log at " << staged_log_path_.value();
250 failed_upload_count_.Set(0);
251 }
252}
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800253
254bool UploadService::AreMetricsEnabled() {
255 return base::PathExists(consent_file_);
256}