From 726339c7e8bd7c1e07031cfda3936debca975831 Mon Sep 17 00:00:00 2001 From: Jin Qian Date: Fri, 17 Mar 2017 16:36:59 -0700 Subject: [PATCH] storaged: read emmc health data from sysfs Sysfs data is straightforward so we don't need parsing anymore. Also removed periodical check since data is set only once during driver initialization. Checking at every device boot or storaged restart should be sufficient to monitor long term status change. Test: adb logcat -d -b events | grep storaged_emmc_info Bug: 36228467 Change-Id: I2a181f52c9f19de1e679a3a905aaebafe4d08227 --- storaged/README.properties | 1 - storaged/include/storaged.h | 6 -- storaged/include/storaged_info.h | 39 +++++------ storaged/main.cpp | 6 +- storaged/storaged.cpp | 9 --- storaged/storaged_info.cpp | 111 ++++++++++++++++++++----------- storaged/tests/storaged_test.cpp | 20 ------ 7 files changed, 89 insertions(+), 103 deletions(-) diff --git a/storaged/README.properties b/storaged/README.properties index 70e6026f0..2d8397fc8 100644 --- a/storaged/README.properties +++ b/storaged/README.properties @@ -1,6 +1,5 @@ ro.storaged.event.interval # interval storaged scans for IO stats, in seconds ro.storaged.event.perf_check # check for time spent in event loop, in microseconds ro.storaged.disk_stats_pub # interval storaged publish disk stats, in seconds -ro.storaged.emmc_info_pub # interval storaged publish emmc info, in seconds ro.storaged.uid_io.interval # interval storaged checks Per UID IO usage, in seconds ro.storaged.uid_io.threshold # Per UID IO usage limit, in bytes diff --git a/storaged/include/storaged.h b/storaged/include/storaged.h index bd1391c98..b6a0850c8 100644 --- a/storaged/include/storaged.h +++ b/storaged/include/storaged.h @@ -230,7 +230,6 @@ public: // Periodic chores intervals in seconds #define DEFAULT_PERIODIC_CHORES_INTERVAL_UNIT ( 60 ) #define DEFAULT_PERIODIC_CHORES_INTERVAL_DISK_STATS_PUBLISH ( 3600 ) -#define DEFAULT_PERIODIC_CHORES_INTERVAL_EMMC_INFO_PUBLISH ( 86400 ) #define DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO ( 3600 ) #define DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO_LIMIT (300) @@ -240,7 +239,6 @@ public: struct storaged_config { int periodic_chores_interval_unit; int periodic_chores_interval_disk_stats_publish; - int periodic_chores_interval_emmc_info_publish; int periodic_chores_interval_uid_io; bool proc_uid_io_available; // whether uid_io is accessible bool diskstats_available; // whether diskstats is accessible @@ -253,7 +251,6 @@ private: storaged_config mConfig; disk_stats_publisher mDiskStats; disk_stats_monitor mDsm; - storage_info_t *info = nullptr; uid_monitor mUidm; time_t mStarttime; public: @@ -264,9 +261,6 @@ public: void pause(void) { sleep(mConfig.periodic_chores_interval_unit); } - void set_storage_info(storage_info_t *storage_info) { - info = storage_info; - } time_t get_starttime(void) { return mStarttime; diff --git a/storaged/include/storaged_info.h b/storaged/include/storaged_info.h index cb5b8a8e2..cfcdd7f22 100644 --- a/storaged/include/storaged_info.h +++ b/storaged/include/storaged_info.h @@ -24,43 +24,34 @@ friend class test_case_name##_##test_name##_Test using namespace std; -// two characters in string for each byte -struct str_hex { - char str[2]; -}; - class storage_info_t { protected: FRIEND_TEST(storaged_test, storage_info_t); - uint8_t eol; // pre-eol (end of life) information - uint8_t lifetime_a; // device life time estimation (type A) - uint8_t lifetime_b; // device life time estimation (type B) + uint16_t eol; // pre-eol (end of life) information + uint16_t lifetime_a; // device life time estimation (type A) + uint16_t lifetime_b; // device life time estimation (type B) string version; // version string -public: void publish(); +public: + storage_info_t() : eol(0), lifetime_a(0), lifetime_b(0) {} virtual ~storage_info_t() {} - virtual bool init() = 0; - virtual bool update() = 0; + virtual bool report() = 0; }; class emmc_info_t : public storage_info_t { private: - // minimum size of a ext_csd file - const int EXT_CSD_FILE_MIN_SIZE = 1024; - // List of interesting offsets - const size_t EXT_CSD_REV_IDX = 192 * sizeof(str_hex); - const size_t EXT_PRE_EOL_INFO_IDX = 267 * sizeof(str_hex); - const size_t EXT_DEVICE_LIFE_TIME_EST_A_IDX = 268 * sizeof(str_hex); - const size_t EXT_DEVICE_LIFE_TIME_EST_B_IDX = 269 * sizeof(str_hex); - - const char* ext_csd_file = "/d/mmc0/mmc0:0001/ext_csd"; - const char* emmc_ver_str[8] = { - "4.0", "4.1", "4.2", "4.3", "Obsolete", "4.41", "4.5", "5.0" + const string emmc_sysfs = "/sys/bus/mmc/devices/mmc0:0001/"; + const string emmc_debugfs = "/d/mmc0/mmc0:0001/ext_csd"; + const char* emmc_ver_str[9] = { + "4.0", "4.1", "4.2", "4.3", "Obsolete", "4.41", "4.5", "5.0", "5.1" }; public: virtual ~emmc_info_t() {} - bool init(); - bool update(); + bool report(); + bool report_sysfs(); + bool report_debugfs(); }; +void report_storage_health(); + #endif /* _STORAGED_INFO_H_ */ diff --git a/storaged/main.cpp b/storaged/main.cpp index e25298b12..2f2273dc1 100644 --- a/storaged/main.cpp +++ b/storaged/main.cpp @@ -43,7 +43,6 @@ #include storaged_t storaged; -emmc_info_t emmc_info; // Function of storaged's main thread void* storaged_main(void* s) { @@ -114,10 +113,7 @@ int main(int argc, char** argv) { } if (flag_main_service) { // start main thread - if (emmc_info.init()) { - storaged.set_storage_info(&emmc_info); - } - + report_storage_health(); // Start the main thread of storaged pthread_t storaged_main_thread; errno = pthread_create(&storaged_main_thread, NULL, storaged_main, &storaged); diff --git a/storaged/storaged.cpp b/storaged/storaged.cpp index 88fbb7a3c..72bb6e23d 100644 --- a/storaged/storaged.cpp +++ b/storaged/storaged.cpp @@ -203,9 +203,6 @@ storaged_t::storaged_t(void) { mConfig.periodic_chores_interval_disk_stats_publish = property_get_int32("ro.storaged.disk_stats_pub", DEFAULT_PERIODIC_CHORES_INTERVAL_DISK_STATS_PUBLISH); - mConfig.periodic_chores_interval_emmc_info_publish = - property_get_int32("ro.storaged.emmc_info_pub", DEFAULT_PERIODIC_CHORES_INTERVAL_EMMC_INFO_PUBLISH); - mConfig.periodic_chores_interval_uid_io = property_get_int32("ro.storaged.uid_io.interval", DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO); @@ -221,12 +218,6 @@ void storaged_t::event(void) { } } - if (info && mTimer && - (mTimer % mConfig.periodic_chores_interval_emmc_info_publish) == 0) { - info->update(); - info->publish(); - } - if (mConfig.proc_uid_io_available && mTimer && (mTimer % mConfig.periodic_chores_interval_uid_io) == 0) { mUidm.report(); diff --git a/storaged/storaged_info.cpp b/storaged/storaged_info.cpp index 73d611c04..1a5da411f 100644 --- a/storaged/storaged_info.cpp +++ b/storaged/storaged_info.cpp @@ -16,83 +16,118 @@ #define LOG_TAG "storaged" +#include #include #include -#include #include +#include #include #include "storaged.h" using namespace std; -using namespace android; using namespace android::base; +void report_storage_health() +{ + emmc_info_t mmc; + mmc.report(); +} + void storage_info_t::publish() { - if (eol == 0 && lifetime_a == 0 && lifetime_b == 0) { - return; - } - android_log_event_list(EVENTLOGTAG_EMMCINFO) << version << eol << lifetime_a << lifetime_b << LOG_ID_EVENTS; } -bool emmc_info_t::init() +bool emmc_info_t::report() +{ + if (!report_sysfs() && !report_debugfs()) + return false; + + publish(); + return true; +} + +bool emmc_info_t::report_sysfs() { string buffer; - if (!ReadFileToString(ext_csd_file, &buffer) || - buffer.length() < (size_t)EXT_CSD_FILE_MIN_SIZE) { + uint16_t rev = 0; + + if (!ReadFileToString(emmc_sysfs + "rev", &buffer)) { return false; } - string ver_str = buffer.substr(EXT_CSD_REV_IDX, sizeof(str_hex)); - uint8_t ext_csd_rev; - if (!ParseUint(ver_str, &ext_csd_rev)) { - LOG_TO(SYSTEM, ERROR) << "Failure on parsing EXT_CSD_REV."; + if (sscanf(buffer.c_str(), "0x%hx", &rev) < 1 || + rev < 7 || rev > ARRAY_SIZE(emmc_ver_str)) { return false; } version = "emmc "; - version += (ext_csd_rev < ARRAY_SIZE(emmc_ver_str)) ? - emmc_ver_str[ext_csd_rev] : "Unknown"; + version += emmc_ver_str[rev]; - if (ext_csd_rev < 7) { + if (!ReadFileToString(emmc_sysfs + "pre_eol_info", &buffer)) { return false; } - return update(); -} - -bool emmc_info_t::update() -{ - string buffer; - if (!ReadFileToString(ext_csd_file, &buffer) || - buffer.length() < (size_t)EXT_CSD_FILE_MIN_SIZE) { + if (sscanf(buffer.c_str(), "%hx", &eol) < 1 || eol == 0) { return false; } - string str = buffer.substr(EXT_PRE_EOL_INFO_IDX, sizeof(str_hex)); - if (!ParseUint(str, &eol)) { - LOG_TO(SYSTEM, ERROR) << "Failure on parsing EXT_PRE_EOL_INFO."; + if (!ReadFileToString(emmc_sysfs + "life_time", &buffer)) { return false; } - str = buffer.substr(EXT_DEVICE_LIFE_TIME_EST_A_IDX, sizeof(str_hex)); - if (!ParseUint(str, &lifetime_a)) { - LOG_TO(SYSTEM, ERROR) - << "Failure on parsing EXT_DEVICE_LIFE_TIME_EST_TYP_A."; - return false; - } - - str = buffer.substr(EXT_DEVICE_LIFE_TIME_EST_B_IDX, sizeof(str_hex)); - if (!ParseUint(str, &lifetime_b)) { - LOG_TO(SYSTEM, ERROR) - << "Failure on parsing EXT_DEVICE_LIFE_TIME_EST_TYP_B."; + if (sscanf(buffer.c_str(), "0x%hx 0x%hx", &lifetime_a, &lifetime_b) < 2 || + (lifetime_a == 0 && lifetime_b == 0)) { return false; } return true; } + +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; + +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; +} \ No newline at end of file diff --git a/storaged/tests/storaged_test.cpp b/storaged/tests/storaged_test.cpp index e335cad87..b103ac1ec 100644 --- a/storaged/tests/storaged_test.cpp +++ b/storaged/tests/storaged_test.cpp @@ -29,7 +29,6 @@ #define MMC_DISK_STATS_PATH "/sys/block/mmcblk0/stat" #define SDA_DISK_STATS_PATH "/sys/block/sda/stat" -#define EMMC_EXT_CSD_PATH "/d/mmc0/mmc0:0001/ext_csd" static void pause(uint32_t sec) { const char* path = "/cache/test"; @@ -58,13 +57,8 @@ static void pause(uint32_t sec) { const char* DISK_STATS_PATH; TEST(storaged_test, retvals) { struct disk_stats stats; - emmc_info_t info; memset(&stats, 0, sizeof(struct disk_stats)); - if (info.init()) { - EXPECT_TRUE(info.update()); - } - if (access(MMC_DISK_STATS_PATH, R_OK) >= 0) { DISK_STATS_PATH = MMC_DISK_STATS_PATH; } else if (access(SDA_DISK_STATS_PATH, R_OK) >= 0) { @@ -127,20 +121,6 @@ TEST(storaged_test, disk_stats) { } } -TEST(storaged_test, storage_info_t) { - emmc_info_t info; - - if (access(EMMC_EXT_CSD_PATH, R_OK) >= 0) { - int ret = info.init(); - if (ret) { - EXPECT_TRUE(info.version.empty()); - ASSERT_TRUE(info.update()); - // update should put something in info. - EXPECT_TRUE(info.eol || info.lifetime_a || info.lifetime_b); - } - } -} - static double mean(std::deque nums) { double sum = 0.0; for (uint32_t i : nums) {