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 "metrics/metrics_library.h" 18 19 #include <base/logging.h> 20 #include <base/strings/stringprintf.h> 21 #include <binder/IServiceManager.h> 22 #include <errno.h> 23 #include <sys/file.h> 24 #include <sys/stat.h> 25 #include <utils/String16.h> 26 27 #include <cstdio> 28 #include <cstring> 29 30 #include "android/brillo/metrics/IMetricsd.h" 31 #include "constants.h" 32 33 static const char kCrosEventHistogramName[] = "Platform.CrOSEvent"; 34 static const int kCrosEventHistogramMax = 100; 35 static const char kMetricsServiceName[] = "android.brillo.metrics.IMetricsd"; 36 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 46 "Chaps.DatabaseCorrupted", // 3 47 "Chaps.DatabaseRepairFailure", // 4 48 "Chaps.DatabaseCreateFailure", // 5 49 "Attestation.OriginSpecificExhausted", // 6 50 "SpringPowerSupply.Original.High", // 7 51 "SpringPowerSupply.Other.High", // 8 52 "SpringPowerSupply.Original.Low", // 9 53 "SpringPowerSupply.ChargerIdle", // 10 54 "TPM.NonZeroDictionaryAttackCounter", // 11 55 "TPM.EarlyResetDuringCommand", // 12 56 }; 57 58 using android::binder::Status; 59 using android::brillo::metrics::IMetricsd; 60 using android::String16; 61 62 MetricsLibrary::MetricsLibrary() {} 63 MetricsLibrary::~MetricsLibrary() {} 64 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) { 72 if (buffer == nullptr || buffer_size < 1) 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 } 129 return result && (access("/var/run/state/logged-in", F_OK) == 0); 130 } 131 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 143 bool MetricsLibrary::AreMetricsEnabled() { 144 static struct stat stat_buffer; 145 time_t this_check_time = time(nullptr); 146 if (!use_caching_ || this_check_time != cached_enabled_time_) { 147 cached_enabled_time_ = this_check_time; 148 cached_enabled_ = stat(consent_file_.value().data(), &stat_buffer) >= 0; 149 } 150 return cached_enabled_; 151 } 152 153 void MetricsLibrary::Init() { 154 base::FilePath dir = base::FilePath(metrics::kSharedMetricsDirectory); 155 consent_file_ = dir.Append(metrics::kConsentFileName); 156 cached_enabled_ = false; 157 cached_enabled_time_ = 0; 158 use_caching_ = true; 159 } 160 161 void MetricsLibrary::InitWithNoCaching() { 162 Init(); 163 use_caching_ = false; 164 } 165 166 void MetricsLibrary::InitForTest(const base::FilePath& metrics_directory) { 167 consent_file_ = metrics_directory.Append(metrics::kConsentFileName); 168 cached_enabled_ = false; 169 cached_enabled_time_ = 0; 170 use_caching_ = true; 171 } 172 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(); 179 } 180 181 bool MetricsLibrary::SendEnumToUMA(const std::string& name, 182 int sample, 183 int max) { 184 return CheckService() && 185 metricsd_proxy_->recordLinearHistogram(String16(name.c_str()), sample, 186 max) 187 .isOk(); 188 } 189 190 bool MetricsLibrary::SendBoolToUMA(const std::string& name, bool sample) { 191 return CheckService() && 192 metricsd_proxy_->recordLinearHistogram(String16(name.c_str()), 193 sample ? 1 : 0, 2) 194 .isOk(); 195 } 196 197 bool MetricsLibrary::SendSparseToUMA(const std::string& name, int sample) { 198 return CheckService() && 199 metricsd_proxy_->recordSparseHistogram(String16(name.c_str()), sample) 200 .isOk(); 201 } 202 203 bool MetricsLibrary::SendCrashToUMA(const char* crash_kind) { 204 return CheckService() && 205 metricsd_proxy_->recordCrash(String16(crash_kind)).isOk(); 206 } 207 208 bool MetricsLibrary::SendCrosEventToUMA(const std::string& event) { 209 for (size_t i = 0; i < arraysize(kCrosEventNames); i++) { 210 if (strcmp(event.c_str(), kCrosEventNames[i]) == 0) { 211 return SendEnumToUMA(kCrosEventHistogramName, i, kCrosEventHistogramMax); 212 } 213 } 214 return false; 215 } 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 } 227