/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef METRICS_UPLOADER_UPLOAD_SERVICE_H_ #define METRICS_UPLOADER_UPLOAD_SERVICE_H_ #include <memory> #include <string> #include <base/metrics/histogram_base.h> #include <base/metrics/histogram_flattener.h> #include <base/metrics/histogram_snapshot_manager.h> #include <brillo/daemons/daemon.h> #include "persistent_integer.h" #include "uploader/crash_counters.h" #include "uploader/metrics_log.h" #include "uploader/metricsd_service_runner.h" #include "uploader/proto/chrome_user_metrics_extension.pb.h" #include "uploader/sender.h" #include "uploader/system_profile_cache.h" class SystemProfileSetter; // Service responsible for backing up the currently aggregated metrics to disk // and uploading them periodically to the server. // // A given metrics sample can be in one of three locations. // * in-memory metrics: in memory aggregated metrics, waiting to be staged for // upload. // * saved log: protobuf message, written to disk periodically and on shutdown // to make a backup of metrics data for uploading later. // * staged log: protobuf message waiting to be uploaded. // // The service works as follows: // On startup, we create the in-memory metrics from the saved log if it exists. // // Periodically (every |disk_persistence_interval_| seconds), we take a snapshot // of the in-memory metrics and save them to disk. // // Periodically (every |upload_interval| seconds), we: // * take a snapshot of the in-memory metrics and create the staged log // * save the staged log to disk to avoid losing it if metricsd or the system // crashes between two uploads. // * delete the last saved log: all the metrics contained in it are also in the // newly created staged log. // // On shutdown (SIGINT or SIGTERM), we save the in-memory metrics to disk. // // Note: the in-memory metrics can be stored in |current_log_| or // base::StatisticsRecorder. class UploadService : public base::HistogramFlattener, public brillo::Daemon { public: UploadService(const std::string& server, const base::TimeDelta& upload_interval, const base::TimeDelta& disk_persistence_interval, const base::FilePath& private_metrics_directory, const base::FilePath& shared_metrics_directory); // Initializes the upload service. int OnInit() override; // Cleans up the internal state before exiting. void OnShutdown(int* exit_code) override; // Starts a new log. The log needs to be regenerated after each successful // launch as it is destroyed when staging the log. void StartNewLog(); // Saves the current metrics to a file. void PersistToDisk(); // Triggers an upload event. void UploadEvent(); // Sends the staged log. void SendStagedLog(); // Implements inconsistency detection to match HistogramFlattener's // interface. void InconsistencyDetected( base::HistogramBase::Inconsistency problem) override {} void UniqueInconsistencyDetected( base::HistogramBase::Inconsistency problem) override {} void InconsistencyDetectedInLoggedCount(int amount) override {} private: friend class UploadServiceTest; FRIEND_TEST(UploadServiceTest, CanSendMultipleTimes); FRIEND_TEST(UploadServiceTest, CorruptedSavedLog); FRIEND_TEST(UploadServiceTest, CurrentLogSavedAndResumed); FRIEND_TEST(UploadServiceTest, DiscardLogsAfterTooManyFailedUpload); FRIEND_TEST(UploadServiceTest, EmptyLogsAreNotSent); FRIEND_TEST(UploadServiceTest, FailedSendAreRetried); FRIEND_TEST(UploadServiceTest, LogContainsAggregatedValues); FRIEND_TEST(UploadServiceTest, LogContainsCrashCounts); FRIEND_TEST(UploadServiceTest, LogEmptyAfterUpload); FRIEND_TEST(UploadServiceTest, LogEmptyByDefault); FRIEND_TEST(UploadServiceTest, LogFromTheMetricsLibrary); FRIEND_TEST(UploadServiceTest, LogKernelCrash); FRIEND_TEST(UploadServiceTest, LogUncleanShutdown); FRIEND_TEST(UploadServiceTest, LogUserCrash); FRIEND_TEST(UploadServiceTest, PersistEmptyLog); FRIEND_TEST(UploadServiceTest, UnknownCrashIgnored); FRIEND_TEST(UploadServiceTest, ValuesInConfigFileAreSent); // Initializes the upload service for testing. void InitForTest(SystemProfileSetter* setter); // If a staged log fails to upload more than kMaxFailedUpload times, it // will be discarded. static const int kMaxFailedUpload; // Loads the log saved to disk if it exists. void LoadSavedLog(); // Resets the internal state. void Reset(); // Returns true iff metrics reporting is enabled. bool AreMetricsEnabled(); // Event callback for handling Upload events. void UploadEventCallback(); // Event callback for handling Persist events. void PersistEventCallback(); // Aggregates all histogram available in memory and store them in the current // log. void GatherHistograms(); // Callback for HistogramSnapshotManager to store the histograms. void RecordDelta(const base::HistogramBase& histogram, const base::HistogramSamples& snapshot) override; // Compiles all the samples received into a single protobuf and adds all // system information. void StageCurrentLog(); // Returns true iff a log is staged. bool HasStagedLog(); // Remove the staged log iff the upload failed more than |kMaxFailedUpload|. void RemoveFailedLog(); // Returns the current log. If there is no current log, creates it first. MetricsLog* GetOrCreateCurrentLog(); std::unique_ptr<SystemProfileSetter> system_profile_setter_; base::HistogramSnapshotManager histogram_snapshot_manager_; std::unique_ptr<Sender> sender_; chromeos_metrics::PersistentInteger failed_upload_count_; std::unique_ptr<MetricsLog> current_log_; std::shared_ptr<CrashCounters> counters_; base::TimeDelta upload_interval_; base::TimeDelta disk_persistence_interval_; MetricsdServiceRunner metricsd_service_runner_; base::FilePath consent_file_; base::FilePath staged_log_path_; base::FilePath saved_log_path_; bool testing_; }; #endif // METRICS_UPLOADER_UPLOAD_SERVICE_H_