storaged: rewrite emmc info class

Test: adb logcat -d -b events | grep storaged_emmc_info
Bug: 36228467
Change-Id: Ib799e60ed65661a9fb99be8ad4c930f547339975
This commit is contained in:
Jin Qian 2017-03-15 19:03:06 -07:00
parent bb82a5a53c
commit 4fc338e60b
8 changed files with 192 additions and 173 deletions

View File

@ -16,6 +16,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
storaged.cpp \
storaged_info.cpp \
storaged_service.cpp \
storaged_utils.cpp \
storaged_uid_monitor.cpp \

View File

@ -28,6 +28,7 @@
#include <batteryservice/IBatteryPropertiesListener.h>
#include "storaged_info.h"
#include "storaged_uid_monitor.h"
using namespace android;
@ -44,6 +45,8 @@ friend class test_case_name##_##test_name##_Test
#define debuginfo(...)
#endif
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#define SECTOR_SIZE ( 512 )
#define SEC_TO_MSEC ( 1000 )
#define MSEC_TO_USEC ( 1000 )
@ -83,15 +86,7 @@ struct disk_stats {
double io_avg; // average io_in_flight for accumulate calculations
};
#define MMC_VER_STR_LEN ( 9 ) // maximum length of the MMC version string, including NULL terminator
// minimum size of a ext_csd file
#define EXT_CSD_FILE_MIN_SIZE ( 1024 )
struct emmc_info {
int eol; // pre-eol (end of life) information
int lifetime_a; // device life time estimation (type A)
int lifetime_b; // device life time estimation (type B)
char mmc_ver[MMC_VER_STR_LEN]; // device version string
};
struct disk_perf {
uint32_t read_perf; // read speed (kbytes/s)
@ -232,26 +227,6 @@ public:
void update(void);
};
class emmc_info_t {
private:
struct emmc_info mInfo;
bool mValid;
int mFdEmmc;
public:
emmc_info_t(void) :
mValid(false),
mFdEmmc(-1) {
memset(&mInfo, 0, sizeof(struct emmc_info));
}
~emmc_info_t(void) {}
void publish(void);
void update(void);
void set_emmc_fd(int fd) {
mFdEmmc = fd;
}
};
// Periodic chores intervals in seconds
#define DEFAULT_PERIODIC_CHORES_INTERVAL_UNIT ( 60 )
#define DEFAULT_PERIODIC_CHORES_INTERVAL_DISK_STATS_PUBLISH ( 3600 )
@ -268,7 +243,6 @@ struct storaged_config {
int periodic_chores_interval_emmc_info_publish;
int periodic_chores_interval_uid_io;
bool proc_uid_io_available; // whether uid_io is accessible
bool emmc_available; // whether eMMC est_csd file is readable
bool diskstats_available; // whether diskstats is accessible
int event_time_check_usec; // check how much cputime spent in event loop
};
@ -279,7 +253,7 @@ private:
storaged_config mConfig;
disk_stats_publisher mDiskStats;
disk_stats_monitor mDsm;
emmc_info_t mEmmcInfo;
storage_info_t *info = nullptr;
uid_monitor mUidm;
time_t mStarttime;
public:
@ -290,8 +264,8 @@ public:
void pause(void) {
sleep(mConfig.periodic_chores_interval_unit);
}
void set_privileged_fds(int fd_emmc) {
mEmmcInfo.set_emmc_fd(fd_emmc);
void set_storage_info(storage_info_t *storage_info) {
info = storage_info;
}
time_t get_starttime(void) {

View File

@ -0,0 +1,66 @@
/*
* Copyright (C) 2017 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.
*/
#ifndef _STORAGED_INFO_H_
#define _STORAGED_INFO_H_
#include <string.h>
#define FRIEND_TEST(test_case_name, test_name) \
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)
string version; // version string
public:
void publish();
virtual ~storage_info_t() {}
virtual bool init() = 0;
virtual bool update() = 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"
};
public:
virtual ~emmc_info_t() {}
bool init();
bool update();
};
#endif /* _STORAGED_INFO_H_ */

View File

@ -43,6 +43,7 @@
#include <storaged_utils.h>
storaged_t storaged;
emmc_info_t emmc_info;
// Function of storaged's main thread
void* storaged_main(void* s) {
@ -69,7 +70,6 @@ static void help_message(void) {
int main(int argc, char** argv) {
int flag_main_service = 0;
int flag_dump_uid = 0;
int fd_emmc = -1;
int opt;
for (;;) {
@ -114,12 +114,9 @@ int main(int argc, char** argv) {
}
if (flag_main_service) { // start main thread
static const char mmc0_ext_csd[] = "/d/mmc0/mmc0:0001/ext_csd";
fd_emmc = android_get_control_file(mmc0_ext_csd);
if (fd_emmc < 0)
fd_emmc = TEMP_FAILURE_RETRY(open(mmc0_ext_csd, O_RDONLY));
storaged.set_privileged_fds(fd_emmc);
if (emmc_info.init()) {
storaged.set_storage_info(&emmc_info);
}
// Start the main thread of storaged
pthread_t storaged_main_thread;
@ -134,8 +131,6 @@ int main(int argc, char** argv) {
IPCThreadState::self()->joinThreadPool();
pthread_join(storaged_main_thread, NULL);
close(fd_emmc);
return 0;
}

View File

@ -147,19 +147,6 @@ void disk_stats_monitor::update(void) {
}
}
/* emmc_info_t */
void emmc_info_t::publish(void) {
if (mValid) {
log_event_emmc_info(&mInfo);
}
}
void emmc_info_t::update(void) {
if (mFdEmmc >= 0) {
mValid = parse_emmc_ecsd(mFdEmmc, &mInfo);
}
}
static sp<IBatteryPropertiesRegistrar> get_battery_properties_service() {
sp<IServiceManager> sm = defaultServiceManager();
if (sm == NULL) return NULL;
@ -199,8 +186,6 @@ void storaged_t::init_battery_service() {
/* storaged_t */
storaged_t::storaged_t(void) {
mConfig.emmc_available = (access(EMMC_ECSD_PATH, R_OK) >= 0);
if (access(MMC_DISK_STATS_PATH, R_OK) < 0 && access(SDA_DISK_STATS_PATH, R_OK) < 0) {
mConfig.diskstats_available = false;
} else {
@ -236,10 +221,10 @@ void storaged_t::event(void) {
}
}
if (mConfig.emmc_available && mTimer &&
(mTimer % mConfig.periodic_chores_interval_emmc_info_publish) == 0) {
mEmmcInfo.update();
mEmmcInfo.publish();
if (info && mTimer &&
(mTimer % mConfig.periodic_chores_interval_emmc_info_publish) == 0) {
info->update();
info->publish();
}
if (mConfig.proc_uid_io_available && mTimer &&

View File

@ -0,0 +1,98 @@
/*
* 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 <string.h>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/parseint.h>
#include <log/log_event_list.h>
#include "storaged.h"
using namespace std;
using namespace android;
using namespace android::base;
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()
{
string buffer;
if (!ReadFileToString(ext_csd_file, &buffer) ||
buffer.length() < (size_t)EXT_CSD_FILE_MIN_SIZE) {
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.";
return false;
}
version = "emmc ";
version += (ext_csd_rev < ARRAY_SIZE(emmc_ver_str)) ?
emmc_ver_str[ext_csd_rev] : "Unknown";
if (ext_csd_rev < 7) {
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) {
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.";
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.";
return false;
}
return true;
}

View File

@ -158,93 +158,6 @@ void add_disk_stats(struct disk_stats* src, struct disk_stats* dst) {
}
}
bool parse_emmc_ecsd(int ext_csd_fd, struct emmc_info* info) {
CHECK(ext_csd_fd >= 0);
struct hex {
char str[2];
};
// List of interesting offsets
static const size_t EXT_CSD_REV_IDX = 192 * sizeof(hex);
static const size_t EXT_PRE_EOL_INFO_IDX = 267 * sizeof(hex);
static const size_t EXT_DEVICE_LIFE_TIME_EST_A_IDX = 268 * sizeof(hex);
static const size_t EXT_DEVICE_LIFE_TIME_EST_B_IDX = 269 * sizeof(hex);
// Read file
CHECK(lseek(ext_csd_fd, 0, SEEK_SET) == 0);
std::string buffer;
if (!android::base::ReadFdToString(ext_csd_fd, &buffer)) {
PLOG_TO(SYSTEM, ERROR) << "ReadFdToString failed.";
return false;
}
if (buffer.length() < EXT_CSD_FILE_MIN_SIZE) {
LOG_TO(SYSTEM, ERROR) << "EMMC ext csd file has truncated content. "
<< "File length: " << buffer.length();
return false;
}
std::string sub;
std::stringstream ss;
// Parse EXT_CSD_REV
int ext_csd_rev = -1;
sub = buffer.substr(EXT_CSD_REV_IDX, sizeof(hex));
ss << sub;
ss >> std::hex >> ext_csd_rev;
if (ext_csd_rev < 0) {
LOG_TO(SYSTEM, ERROR) << "Failure on parsing EXT_CSD_REV.";
return false;
}
ss.clear();
static const char* ver_str[] = {
"4.0", "4.1", "4.2", "4.3", "Obsolete", "4.41", "4.5", "5.0"
};
strlcpy(info->mmc_ver,
(ext_csd_rev < (int)(sizeof(ver_str) / sizeof(ver_str[0]))) ?
ver_str[ext_csd_rev] :
"Unknown",
MMC_VER_STR_LEN);
if (ext_csd_rev < 7) {
return 0;
}
// Parse EXT_PRE_EOL_INFO
info->eol = -1;
sub = buffer.substr(EXT_PRE_EOL_INFO_IDX, sizeof(hex));
ss << sub;
ss >> std::hex >> info->eol;
if (info->eol < 0) {
LOG_TO(SYSTEM, ERROR) << "Failure on parsing EXT_PRE_EOL_INFO.";
return false;
}
ss.clear();
// Parse DEVICE_LIFE_TIME_EST
info->lifetime_a = -1;
sub = buffer.substr(EXT_DEVICE_LIFE_TIME_EST_A_IDX, sizeof(hex));
ss << sub;
ss >> std::hex >> info->lifetime_a;
if (info->lifetime_a < 0) {
LOG_TO(SYSTEM, ERROR) << "Failure on parsing EXT_DEVICE_LIFE_TIME_EST_TYP_A.";
return false;
}
ss.clear();
info->lifetime_b = -1;
sub = buffer.substr(EXT_DEVICE_LIFE_TIME_EST_B_IDX, sizeof(hex));
ss << sub;
ss >> std::hex >> info->lifetime_b;
if (info->lifetime_b < 0) {
LOG_TO(SYSTEM, ERROR) << "Failure on parsing EXT_DEVICE_LIFE_TIME_EST_TYP_B.";
return false;
}
ss.clear();
return true;
}
static bool cmp_uid_info(struct uid_info l, struct uid_info r) {
// Compare background I/O first.
for (int i = UID_STATS - 1; i >= 0; i--) {
@ -317,14 +230,3 @@ void log_event_disk_stats(struct disk_stats* stats, const char* type) {
<< LOG_ID_EVENTS;
}
void log_event_emmc_info(struct emmc_info* info) {
// skip if the input structure are all zeros
if (info == NULL) return;
struct emmc_info zero_cmp;
memset(&zero_cmp, 0, sizeof(zero_cmp));
if (memcmp(&zero_cmp, info, sizeof(struct emmc_info)) == 0) return;
android_log_event_list(EVENTLOGTAG_EMMCINFO)
<< info->mmc_ver << info->eol << info->lifetime_a << info->lifetime_b
<< LOG_ID_EVENTS;
}

View File

@ -58,13 +58,11 @@ static void pause(uint32_t sec) {
const char* DISK_STATS_PATH;
TEST(storaged_test, retvals) {
struct disk_stats stats;
struct emmc_info info;
emmc_info_t info;
memset(&stats, 0, sizeof(struct disk_stats));
memset(&info, 0, sizeof(struct emmc_info));
int emmc_fd = open(EMMC_EXT_CSD_PATH, O_RDONLY);
if (emmc_fd >= 0) {
EXPECT_TRUE(parse_emmc_ecsd(emmc_fd, &info));
if (info.init()) {
EXPECT_TRUE(info.update());
}
if (access(MMC_DISK_STATS_PATH, R_OK) >= 0) {
@ -129,17 +127,17 @@ TEST(storaged_test, disk_stats) {
}
}
TEST(storaged_test, emmc_info) {
struct emmc_info info, void_info;
memset(&info, 0, sizeof(struct emmc_info));
memset(&void_info, 0, sizeof(struct emmc_info));
TEST(storaged_test, storage_info_t) {
emmc_info_t info;
if (access(EMMC_EXT_CSD_PATH, R_OK) >= 0) {
int emmc_fd = open(EMMC_EXT_CSD_PATH, O_RDONLY);
ASSERT_GE(emmc_fd, 0);
ASSERT_TRUE(parse_emmc_ecsd(emmc_fd, &info));
// parse_emmc_ecsd() should put something in info.
EXPECT_NE(0, memcmp(&void_info, &info, sizeof(struct emmc_info)));
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);
}
}
}