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 #ifndef METRICS_UPLOADER_UPLOAD_SERVICE_H_
18 #define METRICS_UPLOADER_UPLOAD_SERVICE_H_
19 
20 #include <memory>
21 #include <string>
22 
23 #include <base/metrics/histogram_base.h>
24 #include <base/metrics/histogram_flattener.h>
25 #include <base/metrics/histogram_snapshot_manager.h>
26 #include <brillo/daemons/daemon.h>
27 
28 #include "persistent_integer.h"
29 #include "uploader/crash_counters.h"
30 #include "uploader/metrics_log.h"
31 #include "uploader/metricsd_service_runner.h"
32 #include "uploader/proto/chrome_user_metrics_extension.pb.h"
33 #include "uploader/sender.h"
34 #include "uploader/system_profile_cache.h"
35 
36 class SystemProfileSetter;
37 
38 // Service responsible for backing up the currently aggregated metrics to disk
39 // and uploading them periodically to the server.
40 //
41 // A given metrics sample can be in one of three locations.
42 // * in-memory metrics: in memory aggregated metrics, waiting to be staged for
43 //   upload.
44 // * saved log: protobuf message, written to disk periodically and on shutdown
45 //   to make a backup of metrics data for uploading later.
46 // * staged log: protobuf message waiting to be uploaded.
47 //
48 // The service works as follows:
49 // On startup, we create the in-memory metrics from the saved log if it exists.
50 //
51 // Periodically (every |disk_persistence_interval_| seconds), we take a snapshot
52 // of the in-memory metrics and save them to disk.
53 //
54 // Periodically (every |upload_interval| seconds), we:
55 // * take a snapshot of the in-memory metrics and create the staged log
56 // * save the staged log to disk to avoid losing it if metricsd or the system
57 //   crashes between two uploads.
58 // * delete the last saved log: all the metrics contained in it are also in the
59 //   newly created staged log.
60 //
61 // On shutdown (SIGINT or SIGTERM), we save the in-memory metrics to disk.
62 //
63 // Note: the in-memory metrics can be stored in |current_log_| or
64 // base::StatisticsRecorder.
65 class UploadService : public base::HistogramFlattener, public brillo::Daemon {
66  public:
67   UploadService(const std::string& server,
68                 const base::TimeDelta& upload_interval,
69                 const base::TimeDelta& disk_persistence_interval,
70                 const base::FilePath& private_metrics_directory,
71                 const base::FilePath& shared_metrics_directory);
72 
73   // Initializes the upload service.
74   int OnInit() override;
75 
76   // Cleans up the internal state before exiting.
77   void OnShutdown(int* exit_code) override;
78 
79   // Starts a new log. The log needs to be regenerated after each successful
80   // launch as it is destroyed when staging the log.
81   void StartNewLog();
82 
83   // Saves the current metrics to a file.
84   void PersistToDisk();
85 
86   // Triggers an upload event.
87   void UploadEvent();
88 
89   // Sends the staged log.
90   void SendStagedLog();
91 
92   // Implements inconsistency detection to match HistogramFlattener's
93   // interface.
InconsistencyDetected(base::HistogramBase::Inconsistency problem)94   void InconsistencyDetected(
95       base::HistogramBase::Inconsistency problem) override {}
UniqueInconsistencyDetected(base::HistogramBase::Inconsistency problem)96   void UniqueInconsistencyDetected(
97       base::HistogramBase::Inconsistency problem) override {}
InconsistencyDetectedInLoggedCount(int amount)98   void InconsistencyDetectedInLoggedCount(int amount) override {}
99 
100  private:
101   friend class UploadServiceTest;
102 
103   FRIEND_TEST(UploadServiceTest, CanSendMultipleTimes);
104   FRIEND_TEST(UploadServiceTest, CorruptedSavedLog);
105   FRIEND_TEST(UploadServiceTest, CurrentLogSavedAndResumed);
106   FRIEND_TEST(UploadServiceTest, DiscardLogsAfterTooManyFailedUpload);
107   FRIEND_TEST(UploadServiceTest, EmptyLogsAreNotSent);
108   FRIEND_TEST(UploadServiceTest, FailedSendAreRetried);
109   FRIEND_TEST(UploadServiceTest, LogContainsAggregatedValues);
110   FRIEND_TEST(UploadServiceTest, LogContainsCrashCounts);
111   FRIEND_TEST(UploadServiceTest, LogEmptyAfterUpload);
112   FRIEND_TEST(UploadServiceTest, LogEmptyByDefault);
113   FRIEND_TEST(UploadServiceTest, LogFromTheMetricsLibrary);
114   FRIEND_TEST(UploadServiceTest, LogKernelCrash);
115   FRIEND_TEST(UploadServiceTest, LogUncleanShutdown);
116   FRIEND_TEST(UploadServiceTest, LogUserCrash);
117   FRIEND_TEST(UploadServiceTest, PersistEmptyLog);
118   FRIEND_TEST(UploadServiceTest, UnknownCrashIgnored);
119   FRIEND_TEST(UploadServiceTest, ValuesInConfigFileAreSent);
120 
121   // Initializes the upload service for testing.
122   void InitForTest(SystemProfileSetter* setter);
123 
124   // If a staged log fails to upload more than kMaxFailedUpload times, it
125   // will be discarded.
126   static const int kMaxFailedUpload;
127 
128   // Loads the log saved to disk if it exists.
129   void LoadSavedLog();
130 
131   // Resets the internal state.
132   void Reset();
133 
134   // Returns true iff metrics reporting is enabled.
135   bool AreMetricsEnabled();
136 
137   // Event callback for handling Upload events.
138   void UploadEventCallback();
139 
140   // Event callback for handling Persist events.
141   void PersistEventCallback();
142 
143   // Aggregates all histogram available in memory and store them in the current
144   // log.
145   void GatherHistograms();
146 
147   // Callback for HistogramSnapshotManager to store the histograms.
148   void RecordDelta(const base::HistogramBase& histogram,
149                    const base::HistogramSamples& snapshot) override;
150 
151   // Compiles all the samples received into a single protobuf and adds all
152   // system information.
153   void StageCurrentLog();
154 
155   // Returns true iff a log is staged.
156   bool HasStagedLog();
157 
158   // Remove the staged log iff the upload failed more than |kMaxFailedUpload|.
159   void RemoveFailedLog();
160 
161   // Returns the current log. If there is no current log, creates it first.
162   MetricsLog* GetOrCreateCurrentLog();
163 
164   std::unique_ptr<SystemProfileSetter> system_profile_setter_;
165   base::HistogramSnapshotManager histogram_snapshot_manager_;
166   std::unique_ptr<Sender> sender_;
167   chromeos_metrics::PersistentInteger failed_upload_count_;
168   std::unique_ptr<MetricsLog> current_log_;
169   std::shared_ptr<CrashCounters> counters_;
170 
171   base::TimeDelta upload_interval_;
172   base::TimeDelta disk_persistence_interval_;
173 
174   MetricsdServiceRunner metricsd_service_runner_;
175 
176   base::FilePath consent_file_;
177   base::FilePath staged_log_path_;
178   base::FilePath saved_log_path_;
179 
180   bool testing_;
181 };
182 
183 #endif  // METRICS_UPLOADER_UPLOAD_SERVICE_H_
184