blob: 3e646e0060d119e792d15aa81a86eb835acbfafd [file] [log] [blame]
Jin Qian4fc338e2017-03-15 19:03:06 -07001/*
2 * Copyright (C) 2016 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#define LOG_TAG "storaged"
18
Jin Qian726339c2017-03-17 16:36:59 -070019#include <stdio.h>
Jin Qian4fc338e2017-03-15 19:03:06 -070020#include <string.h>
Jin Qian8847c622017-07-17 15:06:11 -070021#include <sys/statvfs.h>
Jin Qian4fc338e2017-03-15 19:03:06 -070022
Jin Qiand691d6e2017-09-28 16:02:22 -070023#include <numeric>
24
Jin Qian4fc338e2017-03-15 19:03:06 -070025#include <android-base/file.h>
Jin Qian4fc338e2017-03-15 19:03:06 -070026#include <android-base/parseint.h>
Jin Qian726339c2017-03-17 16:36:59 -070027#include <android-base/logging.h>
Jin Qianb90f1ae2017-03-21 16:57:44 -070028#include <android-base/strings.h>
Jin Qian4fc338e2017-03-15 19:03:06 -070029#include <log/log_event_list.h>
30
31#include "storaged.h"
Jin Qiand691d6e2017-09-28 16:02:22 -070032#include "storaged_info.h"
Jin Qian4fc338e2017-03-15 19:03:06 -070033
34using namespace std;
Jin Qiand691d6e2017-09-28 16:02:22 -070035using namespace chrono;
Jin Qian4fc338e2017-03-15 19:03:06 -070036using namespace android::base;
Jin Qiand691d6e2017-09-28 16:02:22 -070037using namespace storaged_proto;
Jin Qian4fc338e2017-03-15 19:03:06 -070038
Yifan Hong5291a672021-12-06 14:29:40 -080039using aidl::android::hardware::health::IHealth;
40using aidl::android::hardware::health::StorageInfo;
Yifan Hong845e35b2018-01-16 16:03:36 -080041
Jin Qian8847c622017-07-17 15:06:11 -070042const string emmc_info_t::emmc_sysfs = "/sys/bus/mmc/devices/mmc0:0001/";
Jin Qian8847c622017-07-17 15:06:11 -070043const char* emmc_info_t::emmc_ver_str[9] = {
44 "4.0", "4.1", "4.2", "4.3", "Obsolete", "4.41", "4.5", "5.0", "5.1"
45};
Jin Qianb90f1ae2017-03-21 16:57:44 -070046
Jin Qian8847c622017-07-17 15:06:11 -070047const string ufs_info_t::health_file = "/sys/devices/soc/624000.ufshc/health";
48
Jin Qian65dea712017-08-29 16:48:20 -070049namespace {
50
51bool FileExists(const std::string& filename)
Jin Qian8847c622017-07-17 15:06:11 -070052{
53 struct stat buffer;
54 return stat(filename.c_str(), &buffer) == 0;
55}
56
Jin Qian65dea712017-08-29 16:48:20 -070057} // namespace
58
Yifan Hong5291a672021-12-06 14:29:40 -080059storage_info_t* storage_info_t::get_storage_info(const shared_ptr<IHealth>& healthService) {
Yifan Hong845e35b2018-01-16 16:03:36 -080060 if (healthService != nullptr) {
61 return new health_storage_info_t(healthService);
62 }
Hridya Valsarajudbac2042019-08-16 14:00:04 -070063 if (FileExists(emmc_info_t::emmc_sysfs)) return new emmc_info_t;
64
Jin Qian8847c622017-07-17 15:06:11 -070065 if (FileExists(ufs_info_t::health_file)) {
66 return new ufs_info_t;
67 }
68 return new storage_info_t;
69}
70
Jin Qiana8533322017-10-13 18:15:34 -070071void storage_info_t::load_perf_history_proto(const IOPerfHistory& perf_history)
Jin Qiand691d6e2017-09-28 16:02:22 -070072{
Jin Qian94b64ef2017-11-09 15:07:18 -080073 Mutex::Autolock _l(si_mutex);
74
Jin Qiand691d6e2017-09-28 16:02:22 -070075 if (!perf_history.has_day_start_sec() ||
76 perf_history.daily_perf_size() > (int)daily_perf.size() ||
77 perf_history.weekly_perf_size() > (int)weekly_perf.size()) {
Tom Cherryb8c11472020-01-10 17:08:15 -080078 LOG(ERROR) << "Invalid IOPerfHistory proto";
Jin Qiand691d6e2017-09-28 16:02:22 -070079 return;
80 }
81
82 day_start_tp = {};
Jin Qian6df3bc62017-10-18 17:52:14 -070083 day_start_tp += chrono::seconds(perf_history.day_start_sec());
Jin Qiand691d6e2017-09-28 16:02:22 -070084
85 nr_samples = perf_history.nr_samples();
Mark Salyzyn0ade88c2018-11-20 08:28:24 -080086 if (nr_samples < recent_perf.size()) {
87 recent_perf.erase(recent_perf.begin() + nr_samples, recent_perf.end());
88 }
89 size_t i = 0;
Jin Qiand691d6e2017-09-28 16:02:22 -070090 for (auto bw : perf_history.recent_perf()) {
Mark Salyzyn0ade88c2018-11-20 08:28:24 -080091 if (i < recent_perf.size()) {
92 recent_perf[i] = bw;
93 } else {
94 recent_perf.push_back(bw);
95 }
96 ++i;
Jin Qiand691d6e2017-09-28 16:02:22 -070097 }
98
99 nr_days = perf_history.nr_days();
Mark Salyzyn0ade88c2018-11-20 08:28:24 -0800100 i = 0;
Jin Qiand691d6e2017-09-28 16:02:22 -0700101 for (auto bw : perf_history.daily_perf()) {
102 daily_perf[i++] = bw;
103 }
104
105 nr_weeks = perf_history.nr_weeks();
106 i = 0;
107 for (auto bw : perf_history.weekly_perf()) {
108 weekly_perf[i++] = bw;
109 }
110}
111
112void storage_info_t::refresh(IOPerfHistory* perf_history)
Jin Qian8847c622017-07-17 15:06:11 -0700113{
114 struct statvfs buf;
115 if (statvfs(userdata_path.c_str(), &buf) != 0) {
Tom Cherryb8c11472020-01-10 17:08:15 -0800116 PLOG(WARNING) << "Failed to get userdata info";
Jin Qian8847c622017-07-17 15:06:11 -0700117 return;
118 }
119
120 userdata_total_kb = buf.f_bsize * buf.f_blocks >> 10;
121 userdata_free_kb = buf.f_bfree * buf.f_blocks >> 10;
Jin Qiand691d6e2017-09-28 16:02:22 -0700122
Jin Qian6df3bc62017-10-18 17:52:14 -0700123 Mutex::Autolock _l(si_mutex);
Jin Qiand691d6e2017-09-28 16:02:22 -0700124
125 perf_history->Clear();
126 perf_history->set_day_start_sec(
Jin Qian6df3bc62017-10-18 17:52:14 -0700127 duration_cast<chrono::seconds>(day_start_tp.time_since_epoch()).count());
Jin Qiand691d6e2017-09-28 16:02:22 -0700128 for (const uint32_t& bw : recent_perf) {
129 perf_history->add_recent_perf(bw);
130 }
131 perf_history->set_nr_samples(nr_samples);
132 for (const uint32_t& bw : daily_perf) {
133 perf_history->add_daily_perf(bw);
134 }
135 perf_history->set_nr_days(nr_days);
136 for (const uint32_t& bw : weekly_perf) {
137 perf_history->add_weekly_perf(bw);
138 }
139 perf_history->set_nr_weeks(nr_weeks);
Jin Qian726339c2017-03-17 16:36:59 -0700140}
141
Jin Qian4fc338e2017-03-15 19:03:06 -0700142void storage_info_t::publish()
143{
Jin Qian4fc338e2017-03-15 19:03:06 -0700144 android_log_event_list(EVENTLOGTAG_EMMCINFO)
145 << version << eol << lifetime_a << lifetime_b
146 << LOG_ID_EVENTS;
147}
148
Jin Qiand691d6e2017-09-28 16:02:22 -0700149void storage_info_t::update_perf_history(uint32_t bw,
150 const time_point<system_clock>& tp)
151{
Jin Qian6df3bc62017-10-18 17:52:14 -0700152 Mutex::Autolock _l(si_mutex);
Jin Qiand691d6e2017-09-28 16:02:22 -0700153
154 if (tp > day_start_tp &&
Jin Qian6df3bc62017-10-18 17:52:14 -0700155 duration_cast<chrono::seconds>(tp - day_start_tp).count() < DAY_TO_SEC) {
Jin Qiand691d6e2017-09-28 16:02:22 -0700156 if (nr_samples >= recent_perf.size()) {
157 recent_perf.push_back(bw);
158 } else {
159 recent_perf[nr_samples] = bw;
160 }
161 nr_samples++;
162 return;
163 }
164
David Anderson7d74a5a2018-03-26 15:15:05 -0700165 if (nr_samples < recent_perf.size()) {
166 recent_perf.erase(recent_perf.begin() + nr_samples, recent_perf.end());
167 }
Jin Qiand691d6e2017-09-28 16:02:22 -0700168
David Anderson7d74a5a2018-03-26 15:15:05 -0700169 uint32_t daily_avg_bw = 0;
170 if (!recent_perf.empty()) {
171 daily_avg_bw = accumulate(recent_perf.begin(), recent_perf.end(), 0) / recent_perf.size();
172 }
Jin Qiand691d6e2017-09-28 16:02:22 -0700173
Jin Qian6df3bc62017-10-18 17:52:14 -0700174 day_start_tp = tp - chrono::seconds(duration_cast<chrono::seconds>(
Jin Qiand691d6e2017-09-28 16:02:22 -0700175 tp.time_since_epoch()).count() % DAY_TO_SEC);
176
177 nr_samples = 0;
178 if (recent_perf.empty())
179 recent_perf.resize(1);
180 recent_perf[nr_samples++] = bw;
181
182 if (nr_days < WEEK_TO_DAYS) {
183 daily_perf[nr_days++] = daily_avg_bw;
184 return;
185 }
186
David Anderson7d74a5a2018-03-26 15:15:05 -0700187 DCHECK(nr_days > 0);
Jin Qiand691d6e2017-09-28 16:02:22 -0700188 uint32_t week_avg_bw = accumulate(daily_perf.begin(),
189 daily_perf.begin() + nr_days, 0) / nr_days;
190
191 nr_days = 0;
192 daily_perf[nr_days++] = daily_avg_bw;
193
194 if (nr_weeks >= YEAR_TO_WEEKS) {
195 nr_weeks = 0;
196 }
197 weekly_perf[nr_weeks++] = week_avg_bw;
198}
199
Jin Qianb049d182017-10-12 17:02:17 -0700200vector<int> storage_info_t::get_perf_history()
Jin Qiand691d6e2017-09-28 16:02:22 -0700201{
Jin Qian6df3bc62017-10-18 17:52:14 -0700202 Mutex::Autolock _l(si_mutex);
Jin Qiand691d6e2017-09-28 16:02:22 -0700203
Jin Qianb049d182017-10-12 17:02:17 -0700204 vector<int> ret(3 + recent_perf.size() + daily_perf.size() + weekly_perf.size());
Jin Qiand691d6e2017-09-28 16:02:22 -0700205
Jin Qianb049d182017-10-12 17:02:17 -0700206 ret[0] = recent_perf.size();
207 ret[1] = daily_perf.size();
208 ret[2] = weekly_perf.size();
209
210 int start = 3;
Jin Qiand691d6e2017-09-28 16:02:22 -0700211 for (size_t i = 0; i < recent_perf.size(); i++) {
212 int idx = (recent_perf.size() + nr_samples - 1 - i) % recent_perf.size();
Jin Qianb049d182017-10-12 17:02:17 -0700213 ret[start + i] = recent_perf[idx];
Jin Qiand691d6e2017-09-28 16:02:22 -0700214 }
215
Jin Qianb049d182017-10-12 17:02:17 -0700216 start += recent_perf.size();
Jin Qiand691d6e2017-09-28 16:02:22 -0700217 for (size_t i = 0; i < daily_perf.size(); i++) {
218 int idx = (daily_perf.size() + nr_days - 1 - i) % daily_perf.size();
Jin Qianb049d182017-10-12 17:02:17 -0700219 ret[start + i] = daily_perf[idx];
Jin Qiand691d6e2017-09-28 16:02:22 -0700220 }
221
Jin Qianb049d182017-10-12 17:02:17 -0700222 start += daily_perf.size();
Jin Qiand691d6e2017-09-28 16:02:22 -0700223 for (size_t i = 0; i < weekly_perf.size(); i++) {
224 int idx = (weekly_perf.size() + nr_weeks - 1 - i) % weekly_perf.size();
Jin Qianb049d182017-10-12 17:02:17 -0700225 ret[start + i] = weekly_perf[idx];
Jin Qiand691d6e2017-09-28 16:02:22 -0700226 }
227
228 return ret;
229}
230
Michael Wachenschwanz37b912b2017-12-14 18:20:26 -0800231uint32_t storage_info_t::get_recent_perf() {
232 Mutex::Autolock _l(si_mutex);
233 if (recent_perf.size() == 0) return 0;
234 return accumulate(recent_perf.begin(), recent_perf.end(), recent_perf.size() / 2) /
235 recent_perf.size();
236}
237
Jin Qian8847c622017-07-17 15:06:11 -0700238void emmc_info_t::report()
Jin Qian726339c2017-03-17 16:36:59 -0700239{
Hridya Valsarajudbac2042019-08-16 14:00:04 -0700240 if (!report_sysfs()) return;
Jin Qian726339c2017-03-17 16:36:59 -0700241
242 publish();
Jin Qian726339c2017-03-17 16:36:59 -0700243}
244
245bool emmc_info_t::report_sysfs()
Jin Qian4fc338e2017-03-15 19:03:06 -0700246{
247 string buffer;
Jin Qian726339c2017-03-17 16:36:59 -0700248 uint16_t rev = 0;
249
250 if (!ReadFileToString(emmc_sysfs + "rev", &buffer)) {
Jin Qian4fc338e2017-03-15 19:03:06 -0700251 return false;
252 }
253
Jin Qian726339c2017-03-17 16:36:59 -0700254 if (sscanf(buffer.c_str(), "0x%hx", &rev) < 1 ||
255 rev < 7 || rev > ARRAY_SIZE(emmc_ver_str)) {
Jin Qian4fc338e2017-03-15 19:03:06 -0700256 return false;
257 }
258
259 version = "emmc ";
Jin Qian726339c2017-03-17 16:36:59 -0700260 version += emmc_ver_str[rev];
Jin Qian4fc338e2017-03-15 19:03:06 -0700261
Jin Qian726339c2017-03-17 16:36:59 -0700262 if (!ReadFileToString(emmc_sysfs + "pre_eol_info", &buffer)) {
Jin Qian4fc338e2017-03-15 19:03:06 -0700263 return false;
264 }
265
Jin Qian726339c2017-03-17 16:36:59 -0700266 if (sscanf(buffer.c_str(), "%hx", &eol) < 1 || eol == 0) {
Jin Qian4fc338e2017-03-15 19:03:06 -0700267 return false;
268 }
269
Jin Qian726339c2017-03-17 16:36:59 -0700270 if (!ReadFileToString(emmc_sysfs + "life_time", &buffer)) {
Jin Qian4fc338e2017-03-15 19:03:06 -0700271 return false;
272 }
273
Jin Qian726339c2017-03-17 16:36:59 -0700274 if (sscanf(buffer.c_str(), "0x%hx 0x%hx", &lifetime_a, &lifetime_b) < 2 ||
275 (lifetime_a == 0 && lifetime_b == 0)) {
Jin Qian4fc338e2017-03-15 19:03:06 -0700276 return false;
277 }
278
279 return true;
280}
Jin Qian726339c2017-03-17 16:36:59 -0700281
Jin Qian8847c622017-07-17 15:06:11 -0700282void ufs_info_t::report()
Jin Qianb90f1ae2017-03-21 16:57:44 -0700283{
284 string buffer;
285 if (!ReadFileToString(health_file, &buffer)) {
Jin Qian8847c622017-07-17 15:06:11 -0700286 return;
Jin Qianb90f1ae2017-03-21 16:57:44 -0700287 }
288
289 vector<string> lines = Split(buffer, "\n");
290 if (lines.empty()) {
Jin Qian8847c622017-07-17 15:06:11 -0700291 return;
Jin Qianb90f1ae2017-03-21 16:57:44 -0700292 }
293
294 char rev[8];
295 if (sscanf(lines[0].c_str(), "ufs version: 0x%7s\n", rev) < 1) {
Jin Qian8847c622017-07-17 15:06:11 -0700296 return;
Jin Qianb90f1ae2017-03-21 16:57:44 -0700297 }
298
299 version = "ufs " + string(rev);
300
301 for (size_t i = 1; i < lines.size(); i++) {
302 char token[32];
303 uint16_t val;
304 int ret;
305 if ((ret = sscanf(lines[i].c_str(),
306 "Health Descriptor[Byte offset 0x%*d]: %31s = 0x%hx",
307 token, &val)) < 2) {
308 continue;
309 }
310
311 if (string(token) == "bPreEOLInfo") {
312 eol = val;
313 } else if (string(token) == "bDeviceLifeTimeEstA") {
314 lifetime_a = val;
315 } else if (string(token) == "bDeviceLifeTimeEstB") {
316 lifetime_b = val;
317 }
318 }
319
320 if (eol == 0 || (lifetime_a == 0 && lifetime_b == 0)) {
Jin Qian8847c622017-07-17 15:06:11 -0700321 return;
Jin Qianb90f1ae2017-03-21 16:57:44 -0700322 }
323
324 publish();
Jin Qianb90f1ae2017-03-21 16:57:44 -0700325}
326
Yifan Hong845e35b2018-01-16 16:03:36 -0800327void health_storage_info_t::report() {
Yifan Hong5291a672021-12-06 14:29:40 -0800328 vector<StorageInfo> halInfos;
329 auto ret = mHealth->getStorageInfo(&halInfos);
330 if (ret.isOk()) {
Greg Kaiser00c5e4c2021-12-08 10:15:04 -0800331 if (halInfos.size() != 0) {
Yifan Hong5291a672021-12-06 14:29:40 -0800332 set_values_from_hal_storage_info(halInfos[0]);
333 publish();
Yifan Hong539ee582018-09-13 09:39:41 -0700334 return;
335 }
Yifan Hong5291a672021-12-06 14:29:40 -0800336 LOG(ERROR) << "getStorageInfo succeeded but size is 0";
337 return;
Yifan Hong845e35b2018-01-16 16:03:36 -0800338 }
Yifan Hong5291a672021-12-06 14:29:40 -0800339 if (ret.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
340 LOG(DEBUG) << "getStorageInfo is not supported on health HAL.";
341 return;
342 }
343 LOG(ERROR) << "getStorageInfo failed with " << ret.getDescription();
Yifan Hong845e35b2018-01-16 16:03:36 -0800344}
345
346void health_storage_info_t::set_values_from_hal_storage_info(const StorageInfo& halInfo) {
347 eol = halInfo.eol;
348 lifetime_a = halInfo.lifetimeA;
349 lifetime_b = halInfo.lifetimeB;
350 version = halInfo.version;
351}