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:
parent
bb82a5a53c
commit
4fc338e60b
|
@ -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 \
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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_ */
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 &&
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue