| Bertrand SIMONNET | 52e5b99 | 2015-08-10 15:18:00 -0700 | [diff] [blame] | 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 | */ | 
| Darin Petkov | 65b0146 | 2010-04-14 13:32:20 -0700 | [diff] [blame] | 16 |  | 
| Bertrand SIMONNET | d83ca80 | 2014-07-09 16:34:29 -0700 | [diff] [blame] | 17 | #include "metrics/metrics_library.h" | 
| Darin Petkov | 65b0146 | 2010-04-14 13:32:20 -0700 | [diff] [blame] | 18 |  | 
| Luigi Semenzato | 41c5450 | 2014-05-13 15:16:24 -0700 | [diff] [blame] | 19 | #include <base/logging.h> | 
|  | 20 | #include <base/strings/stringprintf.h> | 
| Bertrand SIMONNET | 6b8629a | 2015-11-18 13:46:33 -0800 | [diff] [blame] | 21 | #include <binder/IServiceManager.h> | 
| Darin Petkov | 65b0146 | 2010-04-14 13:32:20 -0700 | [diff] [blame] | 22 | #include <errno.h> | 
|  | 23 | #include <sys/file.h> | 
| Ken Mixter | 4c5daa4 | 2010-08-26 18:35:06 -0700 | [diff] [blame] | 24 | #include <sys/stat.h> | 
| Bertrand SIMONNET | 6b8629a | 2015-11-18 13:46:33 -0800 | [diff] [blame] | 25 | #include <utils/String16.h> | 
| Darin Petkov | 4fcb2ac | 2010-04-15 16:40:23 -0700 | [diff] [blame] | 26 |  | 
| Darin Petkov | 4fcb2ac | 2010-04-15 16:40:23 -0700 | [diff] [blame] | 27 | #include <cstdio> | 
|  | 28 | #include <cstring> | 
| Darin Petkov | 65b0146 | 2010-04-14 13:32:20 -0700 | [diff] [blame] | 29 |  | 
| Bertrand SIMONNET | 6b8629a | 2015-11-18 13:46:33 -0800 | [diff] [blame] | 30 | #include "android/brillo/metrics/IMetricsd.h" | 
| Bertrand SIMONNET | bd3505e | 2015-08-04 14:04:51 -0700 | [diff] [blame] | 31 | #include "constants.h" | 
| Chris Masone | e10b548 | 2013-02-14 12:15:35 -0800 | [diff] [blame] | 32 |  | 
| Luigi Semenzato | 3268422 | 2013-03-13 10:53:55 -0700 | [diff] [blame] | 33 | static const char kCrosEventHistogramName[] = "Platform.CrOSEvent"; | 
|  | 34 | static const int kCrosEventHistogramMax = 100; | 
| Bertrand SIMONNET | 6b8629a | 2015-11-18 13:46:33 -0800 | [diff] [blame] | 35 | static const char kMetricsServiceName[] = "android.brillo.metrics.IMetricsd"; | 
| Darin Petkov | 65b0146 | 2010-04-14 13:32:20 -0700 | [diff] [blame] | 36 |  | 
| Chih-Chung Chang | 6844c06 | 2013-04-01 14:27:39 +0800 | [diff] [blame] | 37 | /* Add new cros events here. | 
|  | 38 | * | 
|  | 39 | * The index of the event is sent in the message, so please do not | 
|  | 40 | * reorder the names. | 
|  | 41 | */ | 
|  | 42 | static const char *kCrosEventNames[] = { | 
|  | 43 | "ModemManagerCommandSendFailure",  // 0 | 
|  | 44 | "HwWatchdogReboot",  // 1 | 
|  | 45 | "Cras.NoCodecsFoundAtBoot",  // 2 | 
| Darren Krahn | 6e55c115 | 2013-07-19 14:09:50 -0700 | [diff] [blame] | 46 | "Chaps.DatabaseCorrupted",  // 3 | 
|  | 47 | "Chaps.DatabaseRepairFailure",  // 4 | 
|  | 48 | "Chaps.DatabaseCreateFailure",  // 5 | 
| Darren Krahn | 86830ba | 2013-07-26 13:37:20 -0700 | [diff] [blame] | 49 | "Attestation.OriginSpecificExhausted",  // 6 | 
| Luigi Semenzato | e57398a | 2013-11-11 14:24:44 -0800 | [diff] [blame] | 50 | "SpringPowerSupply.Original.High",  // 7 | 
|  | 51 | "SpringPowerSupply.Other.High",  // 8 | 
| Luigi Semenzato | e8fd968 | 2013-11-13 16:28:43 -0800 | [diff] [blame] | 52 | "SpringPowerSupply.Original.Low",  // 9 | 
|  | 53 | "SpringPowerSupply.ChargerIdle",  // 10 | 
| Darren Krahn | 09a15fa | 2014-02-07 16:51:15 -0800 | [diff] [blame] | 54 | "TPM.NonZeroDictionaryAttackCounter",  // 11 | 
| Luigi Semenzato | 538e209 | 2015-03-19 17:18:24 -0700 | [diff] [blame] | 55 | "TPM.EarlyResetDuringCommand",  // 12 | 
| Chih-Chung Chang | 6844c06 | 2013-04-01 14:27:39 +0800 | [diff] [blame] | 56 | }; | 
|  | 57 |  | 
| Bertrand SIMONNET | 6b8629a | 2015-11-18 13:46:33 -0800 | [diff] [blame] | 58 | using android::binder::Status; | 
|  | 59 | using android::brillo::metrics::IMetricsd; | 
|  | 60 | using android::String16; | 
|  | 61 |  | 
| Bertrand SIMONNET | 2765d0a | 2015-09-09 10:38:20 -0700 | [diff] [blame] | 62 | MetricsLibrary::MetricsLibrary() {} | 
| Daniel Erat | fd15829 | 2014-03-09 21:39:08 -0700 | [diff] [blame] | 63 | MetricsLibrary::~MetricsLibrary() {} | 
|  | 64 |  | 
| Ken Mixter | eafbbdf | 2010-10-01 15:38:42 -0700 | [diff] [blame] | 65 | // We take buffer and buffer_size as parameters in order to simplify testing | 
|  | 66 | // of various alignments of the |device_name| with |buffer_size|. | 
|  | 67 | bool MetricsLibrary::IsDeviceMounted(const char* device_name, | 
|  | 68 | const char* mounts_file, | 
|  | 69 | char* buffer, | 
|  | 70 | int buffer_size, | 
|  | 71 | bool* result) { | 
| Alex Vakulenko | 1459503 | 2014-08-28 14:59:56 -0700 | [diff] [blame] | 72 | if (buffer == nullptr || buffer_size < 1) | 
| Ken Mixter | eafbbdf | 2010-10-01 15:38:42 -0700 | [diff] [blame] | 73 | return false; | 
|  | 74 | int mounts_fd = open(mounts_file, O_RDONLY); | 
|  | 75 | if (mounts_fd < 0) | 
|  | 76 | return false; | 
|  | 77 | // match_offset describes: | 
|  | 78 | //   -1 -- not beginning of line | 
|  | 79 | //   0..strlen(device_name)-1 -- this offset in device_name is next to match | 
|  | 80 | //   strlen(device_name) -- matched full name, just need a space. | 
|  | 81 | int match_offset = 0; | 
|  | 82 | bool match = false; | 
|  | 83 | while (!match) { | 
|  | 84 | int read_size = read(mounts_fd, buffer, buffer_size); | 
|  | 85 | if (read_size <= 0) { | 
|  | 86 | if (errno == -EINTR) | 
|  | 87 | continue; | 
|  | 88 | break; | 
|  | 89 | } | 
|  | 90 | for (int i = 0; i < read_size; ++i) { | 
|  | 91 | if (buffer[i] == '\n') { | 
|  | 92 | match_offset = 0; | 
|  | 93 | continue; | 
|  | 94 | } | 
|  | 95 | if (match_offset < 0) { | 
|  | 96 | continue; | 
|  | 97 | } | 
|  | 98 | if (device_name[match_offset] == '\0') { | 
|  | 99 | if (buffer[i] == ' ') { | 
|  | 100 | match = true; | 
|  | 101 | break; | 
|  | 102 | } | 
|  | 103 | match_offset = -1; | 
|  | 104 | continue; | 
|  | 105 | } | 
|  | 106 |  | 
|  | 107 | if (buffer[i] == device_name[match_offset]) { | 
|  | 108 | ++match_offset; | 
|  | 109 | } else { | 
|  | 110 | match_offset = -1; | 
|  | 111 | } | 
|  | 112 | } | 
|  | 113 | } | 
|  | 114 | close(mounts_fd); | 
|  | 115 | *result = match; | 
|  | 116 | return true; | 
|  | 117 | } | 
|  | 118 |  | 
|  | 119 | bool MetricsLibrary::IsGuestMode() { | 
|  | 120 | char buffer[256]; | 
|  | 121 | bool result = false; | 
|  | 122 | if (!IsDeviceMounted("guestfs", | 
|  | 123 | "/proc/mounts", | 
|  | 124 | buffer, | 
|  | 125 | sizeof(buffer), | 
|  | 126 | &result)) { | 
|  | 127 | return false; | 
|  | 128 | } | 
| Arkaitz Ruiz Alvarez | 9f1a774 | 2011-05-26 12:22:22 -0700 | [diff] [blame] | 129 | return result && (access("/var/run/state/logged-in", F_OK) == 0); | 
| Ken Mixter | eafbbdf | 2010-10-01 15:38:42 -0700 | [diff] [blame] | 130 | } | 
|  | 131 |  | 
| Bertrand SIMONNET | 6b8629a | 2015-11-18 13:46:33 -0800 | [diff] [blame] | 132 | bool MetricsLibrary::CheckService() { | 
|  | 133 | if (metricsd_proxy_.get() && | 
|  | 134 | android::IInterface::asBinder(metricsd_proxy_)->isBinderAlive()) | 
|  | 135 | return true; | 
|  | 136 |  | 
|  | 137 | const String16 name(kMetricsServiceName); | 
|  | 138 | metricsd_proxy_ = android::interface_cast<IMetricsd>( | 
|  | 139 | android::defaultServiceManager()->checkService(name)); | 
|  | 140 | return metricsd_proxy_.get(); | 
|  | 141 | } | 
|  | 142 |  | 
| Ken Mixter | 4c5daa4 | 2010-08-26 18:35:06 -0700 | [diff] [blame] | 143 | bool MetricsLibrary::AreMetricsEnabled() { | 
| Julian Pastarmov | 70b7abd | 2011-08-02 16:10:49 +0200 | [diff] [blame] | 144 | static struct stat stat_buffer; | 
| Alex Vakulenko | 1459503 | 2014-08-28 14:59:56 -0700 | [diff] [blame] | 145 | time_t this_check_time = time(nullptr); | 
| Bertrand SIMONNET | a5b40d0 | 2015-10-02 16:40:51 -0700 | [diff] [blame] | 146 | if (!use_caching_ || this_check_time != cached_enabled_time_) { | 
| Ken Mixter | 4c5daa4 | 2010-08-26 18:35:06 -0700 | [diff] [blame] | 147 | cached_enabled_time_ = this_check_time; | 
| Bertrand SIMONNET | 2765d0a | 2015-09-09 10:38:20 -0700 | [diff] [blame] | 148 | cached_enabled_ = stat(consent_file_.value().data(), &stat_buffer) >= 0; | 
| Ken Mixter | 4c5daa4 | 2010-08-26 18:35:06 -0700 | [diff] [blame] | 149 | } | 
|  | 150 | return cached_enabled_; | 
|  | 151 | } | 
| Darin Petkov | 11b8eb3 | 2010-05-18 11:00:59 -0700 | [diff] [blame] | 152 |  | 
| Darin Petkov | fc91b42 | 2010-05-12 13:05:45 -0700 | [diff] [blame] | 153 | void MetricsLibrary::Init() { | 
| Bertrand SIMONNET | 9d3a4ae | 2015-11-25 13:49:12 -0800 | [diff] [blame] | 154 | base::FilePath dir = base::FilePath(metrics::kSharedMetricsDirectory); | 
| Bertrand SIMONNET | 2765d0a | 2015-09-09 10:38:20 -0700 | [diff] [blame] | 155 | consent_file_ = dir.Append(metrics::kConsentFileName); | 
| Bertrand SIMONNET | 3598d95 | 2015-09-28 11:04:29 -0700 | [diff] [blame] | 156 | cached_enabled_ = false; | 
|  | 157 | cached_enabled_time_ = 0; | 
| Bertrand SIMONNET | a5b40d0 | 2015-10-02 16:40:51 -0700 | [diff] [blame] | 158 | use_caching_ = true; | 
|  | 159 | } | 
|  | 160 |  | 
|  | 161 | void MetricsLibrary::InitWithNoCaching() { | 
|  | 162 | Init(); | 
|  | 163 | use_caching_ = false; | 
| Darin Petkov | fc91b42 | 2010-05-12 13:05:45 -0700 | [diff] [blame] | 164 | } | 
|  | 165 |  | 
| Bertrand SIMONNET | 2765d0a | 2015-09-09 10:38:20 -0700 | [diff] [blame] | 166 | void MetricsLibrary::InitForTest(const base::FilePath& metrics_directory) { | 
| Bertrand SIMONNET | 2765d0a | 2015-09-09 10:38:20 -0700 | [diff] [blame] | 167 | consent_file_ = metrics_directory.Append(metrics::kConsentFileName); | 
| Bertrand SIMONNET | 3598d95 | 2015-09-28 11:04:29 -0700 | [diff] [blame] | 168 | cached_enabled_ = false; | 
|  | 169 | cached_enabled_time_ = 0; | 
| Bertrand SIMONNET | a5b40d0 | 2015-10-02 16:40:51 -0700 | [diff] [blame] | 170 | use_caching_ = true; | 
| Bertrand SIMONNET | 1253186 | 2015-08-31 11:11:57 -0700 | [diff] [blame] | 171 | } | 
|  | 172 |  | 
| Bertrand SIMONNET | 6b8629a | 2015-11-18 13:46:33 -0800 | [diff] [blame] | 173 | bool MetricsLibrary::SendToUMA( | 
|  | 174 | const std::string& name, int sample, int min, int max, int nbuckets) { | 
|  | 175 | return CheckService() && | 
|  | 176 | metricsd_proxy_->recordHistogram(String16(name.c_str()), sample, min, | 
|  | 177 | max, nbuckets) | 
|  | 178 | .isOk(); | 
| Darin Petkov | 65b0146 | 2010-04-14 13:32:20 -0700 | [diff] [blame] | 179 | } | 
| Darin Petkov | 5b7dce1 | 2010-04-21 15:45:10 -0700 | [diff] [blame] | 180 |  | 
| Bertrand SIMONNET | 6b8629a | 2015-11-18 13:46:33 -0800 | [diff] [blame] | 181 | bool MetricsLibrary::SendEnumToUMA(const std::string& name, | 
|  | 182 | int sample, | 
| Darin Petkov | 21cd2c5 | 2010-05-12 15:26:16 -0700 | [diff] [blame] | 183 | int max) { | 
| Bertrand SIMONNET | 6b8629a | 2015-11-18 13:46:33 -0800 | [diff] [blame] | 184 | return CheckService() && | 
|  | 185 | metricsd_proxy_->recordLinearHistogram(String16(name.c_str()), sample, | 
|  | 186 | max) | 
|  | 187 | .isOk(); | 
| Darin Petkov | ed82485 | 2011-01-06 10:51:47 -0800 | [diff] [blame] | 188 | } | 
|  | 189 |  | 
| Nathan Bullock | adc1c23 | 2015-11-06 14:02:45 -0500 | [diff] [blame] | 190 | bool MetricsLibrary::SendBoolToUMA(const std::string& name, bool sample) { | 
| Bertrand SIMONNET | 6b8629a | 2015-11-18 13:46:33 -0800 | [diff] [blame] | 191 | return CheckService() && | 
|  | 192 | metricsd_proxy_->recordLinearHistogram(String16(name.c_str()), | 
|  | 193 | sample ? 1 : 0, 2) | 
|  | 194 | .isOk(); | 
| Nathan Bullock | adc1c23 | 2015-11-06 14:02:45 -0500 | [diff] [blame] | 195 | } | 
|  | 196 |  | 
| Luigi Semenzato | a7ebeb3 | 2013-03-19 15:02:42 -0700 | [diff] [blame] | 197 | bool MetricsLibrary::SendSparseToUMA(const std::string& name, int sample) { | 
| Bertrand SIMONNET | 6b8629a | 2015-11-18 13:46:33 -0800 | [diff] [blame] | 198 | return CheckService() && | 
|  | 199 | metricsd_proxy_->recordSparseHistogram(String16(name.c_str()), sample) | 
|  | 200 | .isOk(); | 
| Luigi Semenzato | a7ebeb3 | 2013-03-19 15:02:42 -0700 | [diff] [blame] | 201 | } | 
|  | 202 |  | 
| Bertrand SIMONNET | 6b8629a | 2015-11-18 13:46:33 -0800 | [diff] [blame] | 203 | bool MetricsLibrary::SendCrashToUMA(const char* crash_kind) { | 
|  | 204 | return CheckService() && | 
|  | 205 | metricsd_proxy_->recordCrash(String16(crash_kind)).isOk(); | 
| Ken Mixter | be2e13b | 2011-01-22 06:15:56 -0800 | [diff] [blame] | 206 | } | 
| Ken Mixter | b2f1709 | 2011-07-22 14:59:51 -0700 | [diff] [blame] | 207 |  | 
| Luigi Semenzato | 3268422 | 2013-03-13 10:53:55 -0700 | [diff] [blame] | 208 | bool MetricsLibrary::SendCrosEventToUMA(const std::string& event) { | 
| Alex Vakulenko | 788d3b6 | 2014-12-11 09:48:46 -0800 | [diff] [blame] | 209 | for (size_t i = 0; i < arraysize(kCrosEventNames); i++) { | 
| Chih-Chung Chang | 6844c06 | 2013-04-01 14:27:39 +0800 | [diff] [blame] | 210 | if (strcmp(event.c_str(), kCrosEventNames[i]) == 0) { | 
|  | 211 | return SendEnumToUMA(kCrosEventHistogramName, i, kCrosEventHistogramMax); | 
|  | 212 | } | 
| Luigi Semenzato | 3268422 | 2013-03-13 10:53:55 -0700 | [diff] [blame] | 213 | } | 
| Chih-Chung Chang | 6844c06 | 2013-04-01 14:27:39 +0800 | [diff] [blame] | 214 | return false; | 
| Luigi Semenzato | 3268422 | 2013-03-13 10:53:55 -0700 | [diff] [blame] | 215 | } | 
| Bertrand SIMONNET | b13527d | 2015-12-02 17:19:40 -0800 | [diff] [blame] | 216 |  | 
|  | 217 | bool MetricsLibrary::GetHistogramsDump(std::string* dump) { | 
|  | 218 | android::String16 temp_dump; | 
|  | 219 | if (!CheckService() || | 
|  | 220 | !metricsd_proxy_->getHistogramsDump(&temp_dump).isOk()) { | 
|  | 221 | return false; | 
|  | 222 | } | 
|  | 223 |  | 
|  | 224 | *dump = android::String8(temp_dump).string(); | 
|  | 225 | return true; | 
|  | 226 | } |