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 UPDATE_ENGINE_METRICS_UTILS_H_ 18 #define UPDATE_ENGINE_METRICS_UTILS_H_ 19 20 #include <chrono> 21 #include <string> 22 #include <string_view> 23 #include <type_traits> 24 #include <utility> 25 26 #include <base/time/time.h> 27 28 #include "update_engine/common/clock_interface.h" 29 #include "update_engine/common/connection_utils.h" 30 #include "update_engine/common/error_code.h" 31 #include "update_engine/common/metrics_constants.h" 32 #include "update_engine/common/metrics_reporter_interface.h" 33 #include "update_engine/common/prefs_interface.h" 34 35 namespace chromeos_update_engine { 36 37 namespace metrics_utils { 38 39 // Transforms a ErrorCode value into a metrics::DownloadErrorCode. 40 // This obviously only works for errors related to downloading so if |code| 41 // is e.g. |ErrorCode::kFilesystemCopierError| then 42 // |kDownloadErrorCodeInputMalformed| is returned. 43 metrics::DownloadErrorCode GetDownloadErrorCode(ErrorCode code); 44 45 // Transforms a ErrorCode value into a metrics::AttemptResult. 46 // 47 // If metrics::AttemptResult::kPayloadDownloadError is returned, you 48 // can use utils::GetDownloadError() to get more detail. 49 metrics::AttemptResult GetAttemptResult(ErrorCode code); 50 51 // Calculates the internet connection type given |type| and |tethering|. 52 metrics::ConnectionType GetConnectionType(ConnectionType type, 53 ConnectionTethering tethering); 54 55 // Returns the persisted value from prefs for the given key. It also 56 // validates that the value returned is non-negative. 57 int64_t GetPersistedValue(std::string_view key, PrefsInterface* prefs); 58 59 // Persists the reboot count of the update attempt to |kPrefsNumReboots|. 60 void SetNumReboots(int64_t num_reboots, PrefsInterface* prefs); 61 62 // Persists the payload attempt number to |kPrefsPayloadAttemptNumber|. 63 void SetPayloadAttemptNumber(int64_t payload_attempt_number, 64 PrefsInterface* prefs); 65 66 // Persists the finished time of an update to the |kPrefsSystemUpdatedMarker|. 67 void SetSystemUpdatedMarker(ClockInterface* clock, PrefsInterface* prefs); 68 69 // Persists the start monotonic time of an update to 70 // |kPrefsUpdateTimestampStart|. 71 void SetUpdateTimestampStart(const base::Time& update_start_time, 72 PrefsInterface* prefs); 73 74 // Persists the start boot time of an update to 75 // |kPrefsUpdateBootTimestampStart|. 76 void SetUpdateBootTimestampStart(const base::Time& update_start_boot_time, 77 PrefsInterface* prefs); 78 79 // Called at program startup if the device booted into a new update. 80 // The |time_to_reboot| parameter contains the (monotonic-clock) duration 81 // from when the update successfully completed (the value in 82 // |kPrefsSystemUpdatedMarker|) until the device was booted into the update 83 // (current monotonic-clock time). 84 bool LoadAndReportTimeToReboot(MetricsReporterInterface* metrics_reporter, 85 PrefsInterface* prefs, 86 ClockInterface* clock); 87 88 template <typename T> 89 class PersistedValue { 90 public: PersistedValue(std::string_view key,PrefsInterface * prefs)91 PersistedValue(std::string_view key, PrefsInterface* prefs) 92 : key_(key), prefs_(prefs) { 93 val_ = metrics_utils::GetPersistedValue(key, prefs); 94 } ~PersistedValue()95 ~PersistedValue() { Flush(true); } Delete()96 void Delete() { 97 val_ = {}; 98 prefs_->Delete(key_); 99 } get()100 T get() const { return val_; } 101 using clock = std::chrono::system_clock; 102 using time_point = clock::time_point; 103 // prefix increment 104 PersistedValue<T>& operator++() { 105 ++val_; 106 Flush(); 107 return *this; 108 } 109 PersistedValue<T>& operator--() { 110 --val_; 111 Flush(); 112 return *this; 113 } 114 PersistedValue<T>& operator+=(T&& t) { 115 val_ += std::forward<T>(t); 116 Flush(); 117 return *this; 118 } 119 PersistedValue<T>& operator-=(T&& t) { 120 val_ -= std::forward<T>(t); 121 Flush(); 122 return *this; 123 } 124 PersistedValue<T>& operator=(T&& t) { 125 val_ = std::forward<T>(t); 126 Flush(); 127 return *this; 128 } 129 void Flush(bool force = false) { 130 auto now = clock::now(); 131 if (now - last_save_ > metrics::kMetricFlushInterval || force) { 132 last_save_ = now; 133 if (std::is_integral_v<T>) { 134 prefs_->SetInt64(key_, val_); 135 } else if (std::is_same_v<T, bool>) { 136 prefs_->SetBoolean(key_, val_); 137 } else { 138 auto value = std::to_string(val_); 139 prefs_->SetString(key_, value); 140 } 141 } 142 } 143 144 private: 145 const std::string_view key_; 146 PrefsInterface* prefs_; 147 T val_; 148 time_point last_save_{}; 149 }; 150 151 } // namespace metrics_utils 152 } // namespace chromeos_update_engine 153 154 #endif // UPDATE_ENGINE_METRICS_UTILS_H_ 155