123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405 |
- /*
- * Copyright (C) 2016 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.
- */
- #define LOG_TAG "storaged"
- #include <stdio.h>
- #include <string.h>
- #include <sys/statvfs.h>
- #include <numeric>
- #include <android-base/file.h>
- #include <android-base/parseint.h>
- #include <android-base/logging.h>
- #include <android-base/strings.h>
- #include <log/log_event_list.h>
- #include "storaged.h"
- #include "storaged_info.h"
- using namespace std;
- using namespace chrono;
- using namespace android::base;
- using namespace storaged_proto;
- using android::hardware::health::V2_0::IHealth;
- using android::hardware::health::V2_0::Result;
- using android::hardware::health::V2_0::StorageInfo;
- const string emmc_info_t::emmc_sysfs = "/sys/bus/mmc/devices/mmc0:0001/";
- const string emmc_info_t::emmc_debugfs = "/d/mmc0/mmc0:0001/ext_csd";
- const char* emmc_info_t::emmc_ver_str[9] = {
- "4.0", "4.1", "4.2", "4.3", "Obsolete", "4.41", "4.5", "5.0", "5.1"
- };
- const string ufs_info_t::health_file = "/sys/devices/soc/624000.ufshc/health";
- namespace {
- bool FileExists(const std::string& filename)
- {
- struct stat buffer;
- return stat(filename.c_str(), &buffer) == 0;
- }
- } // namespace
- storage_info_t* storage_info_t::get_storage_info(const sp<IHealth>& healthService) {
- if (healthService != nullptr) {
- return new health_storage_info_t(healthService);
- }
- if (FileExists(emmc_info_t::emmc_sysfs) ||
- FileExists(emmc_info_t::emmc_debugfs)) {
- return new emmc_info_t;
- }
- if (FileExists(ufs_info_t::health_file)) {
- return new ufs_info_t;
- }
- return new storage_info_t;
- }
- void storage_info_t::load_perf_history_proto(const IOPerfHistory& perf_history)
- {
- Mutex::Autolock _l(si_mutex);
- if (!perf_history.has_day_start_sec() ||
- perf_history.daily_perf_size() > (int)daily_perf.size() ||
- perf_history.weekly_perf_size() > (int)weekly_perf.size()) {
- LOG_TO(SYSTEM, ERROR) << "Invalid IOPerfHistory proto";
- return;
- }
- day_start_tp = {};
- day_start_tp += chrono::seconds(perf_history.day_start_sec());
- nr_samples = perf_history.nr_samples();
- if (nr_samples < recent_perf.size()) {
- recent_perf.erase(recent_perf.begin() + nr_samples, recent_perf.end());
- }
- size_t i = 0;
- for (auto bw : perf_history.recent_perf()) {
- if (i < recent_perf.size()) {
- recent_perf[i] = bw;
- } else {
- recent_perf.push_back(bw);
- }
- ++i;
- }
- nr_days = perf_history.nr_days();
- i = 0;
- for (auto bw : perf_history.daily_perf()) {
- daily_perf[i++] = bw;
- }
- nr_weeks = perf_history.nr_weeks();
- i = 0;
- for (auto bw : perf_history.weekly_perf()) {
- weekly_perf[i++] = bw;
- }
- }
- void storage_info_t::refresh(IOPerfHistory* perf_history)
- {
- struct statvfs buf;
- if (statvfs(userdata_path.c_str(), &buf) != 0) {
- PLOG_TO(SYSTEM, WARNING) << "Failed to get userdata info";
- return;
- }
- userdata_total_kb = buf.f_bsize * buf.f_blocks >> 10;
- userdata_free_kb = buf.f_bfree * buf.f_blocks >> 10;
- Mutex::Autolock _l(si_mutex);
- perf_history->Clear();
- perf_history->set_day_start_sec(
- duration_cast<chrono::seconds>(day_start_tp.time_since_epoch()).count());
- for (const uint32_t& bw : recent_perf) {
- perf_history->add_recent_perf(bw);
- }
- perf_history->set_nr_samples(nr_samples);
- for (const uint32_t& bw : daily_perf) {
- perf_history->add_daily_perf(bw);
- }
- perf_history->set_nr_days(nr_days);
- for (const uint32_t& bw : weekly_perf) {
- perf_history->add_weekly_perf(bw);
- }
- perf_history->set_nr_weeks(nr_weeks);
- }
- void storage_info_t::publish()
- {
- android_log_event_list(EVENTLOGTAG_EMMCINFO)
- << version << eol << lifetime_a << lifetime_b
- << LOG_ID_EVENTS;
- }
- void storage_info_t::update_perf_history(uint32_t bw,
- const time_point<system_clock>& tp)
- {
- Mutex::Autolock _l(si_mutex);
- if (tp > day_start_tp &&
- duration_cast<chrono::seconds>(tp - day_start_tp).count() < DAY_TO_SEC) {
- if (nr_samples >= recent_perf.size()) {
- recent_perf.push_back(bw);
- } else {
- recent_perf[nr_samples] = bw;
- }
- nr_samples++;
- return;
- }
- if (nr_samples < recent_perf.size()) {
- recent_perf.erase(recent_perf.begin() + nr_samples, recent_perf.end());
- }
- uint32_t daily_avg_bw = 0;
- if (!recent_perf.empty()) {
- daily_avg_bw = accumulate(recent_perf.begin(), recent_perf.end(), 0) / recent_perf.size();
- }
- day_start_tp = tp - chrono::seconds(duration_cast<chrono::seconds>(
- tp.time_since_epoch()).count() % DAY_TO_SEC);
- nr_samples = 0;
- if (recent_perf.empty())
- recent_perf.resize(1);
- recent_perf[nr_samples++] = bw;
- if (nr_days < WEEK_TO_DAYS) {
- daily_perf[nr_days++] = daily_avg_bw;
- return;
- }
- DCHECK(nr_days > 0);
- uint32_t week_avg_bw = accumulate(daily_perf.begin(),
- daily_perf.begin() + nr_days, 0) / nr_days;
- nr_days = 0;
- daily_perf[nr_days++] = daily_avg_bw;
- if (nr_weeks >= YEAR_TO_WEEKS) {
- nr_weeks = 0;
- }
- weekly_perf[nr_weeks++] = week_avg_bw;
- }
- vector<int> storage_info_t::get_perf_history()
- {
- Mutex::Autolock _l(si_mutex);
- vector<int> ret(3 + recent_perf.size() + daily_perf.size() + weekly_perf.size());
- ret[0] = recent_perf.size();
- ret[1] = daily_perf.size();
- ret[2] = weekly_perf.size();
- int start = 3;
- for (size_t i = 0; i < recent_perf.size(); i++) {
- int idx = (recent_perf.size() + nr_samples - 1 - i) % recent_perf.size();
- ret[start + i] = recent_perf[idx];
- }
- start += recent_perf.size();
- for (size_t i = 0; i < daily_perf.size(); i++) {
- int idx = (daily_perf.size() + nr_days - 1 - i) % daily_perf.size();
- ret[start + i] = daily_perf[idx];
- }
- start += daily_perf.size();
- for (size_t i = 0; i < weekly_perf.size(); i++) {
- int idx = (weekly_perf.size() + nr_weeks - 1 - i) % weekly_perf.size();
- ret[start + i] = weekly_perf[idx];
- }
- return ret;
- }
- uint32_t storage_info_t::get_recent_perf() {
- Mutex::Autolock _l(si_mutex);
- if (recent_perf.size() == 0) return 0;
- return accumulate(recent_perf.begin(), recent_perf.end(), recent_perf.size() / 2) /
- recent_perf.size();
- }
- void emmc_info_t::report()
- {
- if (!report_sysfs() && !report_debugfs())
- return;
- publish();
- }
- bool emmc_info_t::report_sysfs()
- {
- string buffer;
- uint16_t rev = 0;
- if (!ReadFileToString(emmc_sysfs + "rev", &buffer)) {
- return false;
- }
- if (sscanf(buffer.c_str(), "0x%hx", &rev) < 1 ||
- rev < 7 || rev > ARRAY_SIZE(emmc_ver_str)) {
- return false;
- }
- version = "emmc ";
- version += emmc_ver_str[rev];
- if (!ReadFileToString(emmc_sysfs + "pre_eol_info", &buffer)) {
- return false;
- }
- if (sscanf(buffer.c_str(), "%hx", &eol) < 1 || eol == 0) {
- return false;
- }
- if (!ReadFileToString(emmc_sysfs + "life_time", &buffer)) {
- return false;
- }
- if (sscanf(buffer.c_str(), "0x%hx 0x%hx", &lifetime_a, &lifetime_b) < 2 ||
- (lifetime_a == 0 && lifetime_b == 0)) {
- return false;
- }
- return true;
- }
- namespace {
- const size_t EXT_CSD_FILE_MIN_SIZE = 1024;
- /* 2 characters in string for each byte */
- const size_t EXT_CSD_REV_IDX = 192 * 2;
- const size_t EXT_PRE_EOL_INFO_IDX = 267 * 2;
- const size_t EXT_DEVICE_LIFE_TIME_EST_A_IDX = 268 * 2;
- const size_t EXT_DEVICE_LIFE_TIME_EST_B_IDX = 269 * 2;
- } // namespace
- bool emmc_info_t::report_debugfs()
- {
- string buffer;
- uint16_t rev = 0;
- if (!ReadFileToString(emmc_debugfs, &buffer) ||
- buffer.length() < (size_t)EXT_CSD_FILE_MIN_SIZE) {
- return false;
- }
- string str = buffer.substr(EXT_CSD_REV_IDX, 2);
- if (!ParseUint(str, &rev) ||
- rev < 7 || rev > ARRAY_SIZE(emmc_ver_str)) {
- return false;
- }
- version = "emmc ";
- version += emmc_ver_str[rev];
- str = buffer.substr(EXT_PRE_EOL_INFO_IDX, 2);
- if (!ParseUint(str, &eol)) {
- return false;
- }
- str = buffer.substr(EXT_DEVICE_LIFE_TIME_EST_A_IDX, 2);
- if (!ParseUint(str, &lifetime_a)) {
- return false;
- }
- str = buffer.substr(EXT_DEVICE_LIFE_TIME_EST_B_IDX, 2);
- if (!ParseUint(str, &lifetime_b)) {
- return false;
- }
- return true;
- }
- void ufs_info_t::report()
- {
- string buffer;
- if (!ReadFileToString(health_file, &buffer)) {
- return;
- }
- vector<string> lines = Split(buffer, "\n");
- if (lines.empty()) {
- return;
- }
- char rev[8];
- if (sscanf(lines[0].c_str(), "ufs version: 0x%7s\n", rev) < 1) {
- return;
- }
- version = "ufs " + string(rev);
- for (size_t i = 1; i < lines.size(); i++) {
- char token[32];
- uint16_t val;
- int ret;
- if ((ret = sscanf(lines[i].c_str(),
- "Health Descriptor[Byte offset 0x%*d]: %31s = 0x%hx",
- token, &val)) < 2) {
- continue;
- }
- if (string(token) == "bPreEOLInfo") {
- eol = val;
- } else if (string(token) == "bDeviceLifeTimeEstA") {
- lifetime_a = val;
- } else if (string(token) == "bDeviceLifeTimeEstB") {
- lifetime_b = val;
- }
- }
- if (eol == 0 || (lifetime_a == 0 && lifetime_b == 0)) {
- return;
- }
- publish();
- }
- void health_storage_info_t::report() {
- auto ret = mHealth->getStorageInfo([this](auto result, const auto& halInfos) {
- if (result == Result::NOT_SUPPORTED) {
- LOG_TO(SYSTEM, DEBUG) << "getStorageInfo is not supported on health HAL.";
- return;
- }
- if (result != Result::SUCCESS || halInfos.size() == 0) {
- LOG_TO(SYSTEM, ERROR) << "getStorageInfo failed with result " << toString(result)
- << " and size " << halInfos.size();
- return;
- }
- set_values_from_hal_storage_info(halInfos[0]);
- publish();
- });
- if (!ret.isOk()) {
- LOG_TO(SYSTEM, ERROR) << "getStorageInfo failed with " << ret.description();
- }
- }
- void health_storage_info_t::set_values_from_hal_storage_info(const StorageInfo& halInfo) {
- eol = halInfo.eol;
- lifetime_a = halInfo.lifetimeA;
- lifetime_b = halInfo.lifetimeB;
- version = halInfo.version;
- }
|