Home | History | Annotate | Download | only in uploader
      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 <memory>
     22 #include <string>
     23 
     24 #include <base/bind.h>
     25 #include <base/files/file_util.h>
     26 #include <base/logging.h>
     27 #include <base/memory/scoped_vector.h>
     28 #include <base/message_loop/message_loop.h>
     29 #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>
     35 
     36 #include "constants.h"
     37 #include "uploader/metrics_log.h"
     38 #include "uploader/sender_http.h"
     39 #include "uploader/system_profile_setter.h"
     40 
     41 const int UploadService::kMaxFailedUpload = 10;
     42 
     43 UploadService::UploadService(const std::string& server,
     44                              const base::TimeDelta& upload_interval,
     45                              const base::TimeDelta& disk_persistence_interval,
     46                              const base::FilePath& private_metrics_directory,
     47                              const base::FilePath& shared_metrics_directory)
     48     : brillo::Daemon(),
     49       histogram_snapshot_manager_(this),
     50       sender_(new HttpSender(server)),
     51       failed_upload_count_(metrics::kFailedUploadCountName,
     52                            private_metrics_directory),
     53       counters_(new CrashCounters),
     54       upload_interval_(upload_interval),
     55       disk_persistence_interval_(disk_persistence_interval),
     56       metricsd_service_runner_(counters_) {
     57   staged_log_path_ = private_metrics_directory.Append(metrics::kStagedLogName);
     58   saved_log_path_ = private_metrics_directory.Append(metrics::kSavedLogName);
     59   consent_file_ = shared_metrics_directory.Append(metrics::kConsentFileName);
     60 }
     61 
     62 void UploadService::LoadSavedLog() {
     63   if (base::PathExists(saved_log_path_)) {
     64     GetOrCreateCurrentLog()->LoadFromFile(saved_log_path_);
     65   }
     66 }
     67 
     68 int UploadService::OnInit() {
     69   brillo::Daemon::OnInit();
     70 
     71   base::StatisticsRecorder::Initialize();
     72   metricsd_service_runner_.Start();
     73 
     74   system_profile_setter_.reset(new SystemProfileCache());
     75 
     76   base::MessageLoop::current()->PostDelayedTask(
     77       FROM_HERE,
     78       base::Bind(&UploadService::UploadEventCallback, base::Unretained(this)),
     79       upload_interval_);
     80 
     81   base::MessageLoop::current()->PostDelayedTask(
     82       FROM_HERE,
     83       base::Bind(&UploadService::PersistEventCallback, base::Unretained(this)),
     84       disk_persistence_interval_);
     85 
     86   LoadSavedLog();
     87 
     88   return EX_OK;
     89 }
     90 
     91 void UploadService::OnShutdown(int* exit_code) {
     92   metricsd_service_runner_.Stop();
     93   PersistToDisk();
     94 }
     95 
     96 void UploadService::InitForTest(SystemProfileSetter* setter) {
     97   LoadSavedLog();
     98   system_profile_setter_.reset(setter);
     99 }
    100 
    101 void UploadService::StartNewLog() {
    102   current_log_.reset(new MetricsLog());
    103 }
    104 
    105 void UploadService::UploadEventCallback() {
    106   UploadEvent();
    107 
    108   base::MessageLoop::current()->PostDelayedTask(
    109       FROM_HERE,
    110       base::Bind(&UploadService::UploadEventCallback, base::Unretained(this)),
    111       upload_interval_);
    112 }
    113 
    114 void 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 
    123 void UploadService::PersistToDisk() {
    124   GatherHistograms();
    125   if (current_log_) {
    126     current_log_->SaveToFile(saved_log_path_);
    127   }
    128 }
    129 
    130 void UploadService::UploadEvent() {
    131   // 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()) {
    136     // Previous upload failed, retry sending the logs.
    137     SendStagedLog();
    138     return;
    139   }
    140 
    141   // Previous upload successful, stage another log.
    142   GatherHistograms();
    143   StageCurrentLog();
    144 
    145   // If a log is available for upload, upload it.
    146   if (HasStagedLog()) {
    147     SendStagedLog();
    148   }
    149 }
    150 
    151 void UploadService::SendStagedLog() {
    152   // If metrics are not enabled, discard the log and exit.
    153   if (!AreMetricsEnabled()) {
    154     LOG(INFO) << "Metrics disabled. Don't upload metrics samples.";
    155     base::DeleteFile(staged_log_path_, false);
    156     return;
    157   }
    158 
    159   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";
    167   } else {
    168     VLOG(1) << "uploaded " << staged_log.length() << " bytes";
    169     base::DeleteFile(staged_log_path_, false);
    170   }
    171 
    172   RemoveFailedLog();
    173 }
    174 
    175 void UploadService::Reset() {
    176   base::DeleteFile(staged_log_path_, false);
    177   current_log_.reset();
    178   failed_upload_count_.Set(0);
    179 }
    180 
    181 void UploadService::GatherHistograms() {
    182   base::StatisticsRecorder::Histograms histograms;
    183   base::StatisticsRecorder::GetHistograms(&histograms);
    184 
    185   histogram_snapshot_manager_.PrepareDeltas(
    186       base::Histogram::kNoFlags, base::Histogram::kUmaTargetedHistogramFlag);
    187 
    188   // Gather and reset the crash counters, shared with the binder threads.
    189   unsigned int kernel_crashes = counters_->GetAndResetKernelCrashCount();
    190   unsigned int unclean_shutdowns = counters_->GetAndResetUncleanShutdownCount();
    191   unsigned int user_crashes = counters_->GetAndResetUserCrashCount();
    192 
    193   // Only create a log if the counters have changed.
    194   if (kernel_crashes > 0 || unclean_shutdowns > 0 || user_crashes > 0) {
    195     GetOrCreateCurrentLog()->IncrementKernelCrashCount(kernel_crashes);
    196     GetOrCreateCurrentLog()->IncrementUncleanShutdownCount(unclean_shutdowns);
    197     GetOrCreateCurrentLog()->IncrementUserCrashCount(user_crashes);
    198   }
    199 }
    200 
    201 void UploadService::RecordDelta(const base::HistogramBase& histogram,
    202                                 const base::HistogramSamples& snapshot) {
    203   GetOrCreateCurrentLog()->RecordHistogramDelta(histogram.histogram_name(),
    204                                                 snapshot);
    205 }
    206 
    207 void UploadService::StageCurrentLog() {
    208   // If we haven't logged anything since the last upload, don't upload an empty
    209   // report.
    210   if (!current_log_)
    211     return;
    212 
    213   std::unique_ptr<MetricsLog> staged_log;
    214   staged_log.swap(current_log_);
    215   staged_log->CloseLog();
    216   if (!staged_log->PopulateSystemProfile(system_profile_setter_.get())) {
    217     LOG(WARNING) << "Error while adding metadata to the log. Discarding the "
    218                  << "log.";
    219     return;
    220   }
    221 
    222   if (!base::DeleteFile(saved_log_path_, false)) {
    223     // There is a chance that we will upload the same metrics twice but, if we
    224     // are lucky, the backup should be overridden before that. In doubt, try not
    225     // to lose any metrics.
    226     LOG(ERROR) << "failed to delete the last backup of the current log.";
    227   }
    228 
    229   failed_upload_count_.Set(0);
    230   staged_log->SaveToFile(staged_log_path_);
    231 }
    232 
    233 MetricsLog* UploadService::GetOrCreateCurrentLog() {
    234   if (!current_log_) {
    235     StartNewLog();
    236   }
    237   return current_log_.get();
    238 }
    239 
    240 bool UploadService::HasStagedLog() {
    241   return base::PathExists(staged_log_path_);
    242 }
    243 
    244 void UploadService::RemoveFailedLog() {
    245   if (failed_upload_count_.Get() > kMaxFailedUpload) {
    246     LOG(INFO) << "log failed more than " << kMaxFailedUpload << " times.";
    247     CHECK(base::DeleteFile(staged_log_path_, false))
    248         << "failed to delete staged log at " << staged_log_path_.value();
    249     failed_upload_count_.Set(0);
    250   }
    251 }
    252 
    253 bool UploadService::AreMetricsEnabled() {
    254   return base::PathExists(consent_file_);
    255 }
    256