storaged_info.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. /*
  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. #define LOG_TAG "storaged"
  17. #include <stdio.h>
  18. #include <string.h>
  19. #include <sys/statvfs.h>
  20. #include <numeric>
  21. #include <android-base/file.h>
  22. #include <android-base/parseint.h>
  23. #include <android-base/logging.h>
  24. #include <android-base/strings.h>
  25. #include <log/log_event_list.h>
  26. #include "storaged.h"
  27. #include "storaged_info.h"
  28. using namespace std;
  29. using namespace chrono;
  30. using namespace android::base;
  31. using namespace storaged_proto;
  32. using android::hardware::health::V2_0::IHealth;
  33. using android::hardware::health::V2_0::Result;
  34. using android::hardware::health::V2_0::StorageInfo;
  35. const string emmc_info_t::emmc_sysfs = "/sys/bus/mmc/devices/mmc0:0001/";
  36. const string emmc_info_t::emmc_debugfs = "/d/mmc0/mmc0:0001/ext_csd";
  37. const char* emmc_info_t::emmc_ver_str[9] = {
  38. "4.0", "4.1", "4.2", "4.3", "Obsolete", "4.41", "4.5", "5.0", "5.1"
  39. };
  40. const string ufs_info_t::health_file = "/sys/devices/soc/624000.ufshc/health";
  41. namespace {
  42. bool FileExists(const std::string& filename)
  43. {
  44. struct stat buffer;
  45. return stat(filename.c_str(), &buffer) == 0;
  46. }
  47. } // namespace
  48. storage_info_t* storage_info_t::get_storage_info(const sp<IHealth>& healthService) {
  49. if (healthService != nullptr) {
  50. return new health_storage_info_t(healthService);
  51. }
  52. if (FileExists(emmc_info_t::emmc_sysfs) ||
  53. FileExists(emmc_info_t::emmc_debugfs)) {
  54. return new emmc_info_t;
  55. }
  56. if (FileExists(ufs_info_t::health_file)) {
  57. return new ufs_info_t;
  58. }
  59. return new storage_info_t;
  60. }
  61. void storage_info_t::load_perf_history_proto(const IOPerfHistory& perf_history)
  62. {
  63. Mutex::Autolock _l(si_mutex);
  64. if (!perf_history.has_day_start_sec() ||
  65. perf_history.daily_perf_size() > (int)daily_perf.size() ||
  66. perf_history.weekly_perf_size() > (int)weekly_perf.size()) {
  67. LOG_TO(SYSTEM, ERROR) << "Invalid IOPerfHistory proto";
  68. return;
  69. }
  70. day_start_tp = {};
  71. day_start_tp += chrono::seconds(perf_history.day_start_sec());
  72. nr_samples = perf_history.nr_samples();
  73. if (nr_samples < recent_perf.size()) {
  74. recent_perf.erase(recent_perf.begin() + nr_samples, recent_perf.end());
  75. }
  76. size_t i = 0;
  77. for (auto bw : perf_history.recent_perf()) {
  78. if (i < recent_perf.size()) {
  79. recent_perf[i] = bw;
  80. } else {
  81. recent_perf.push_back(bw);
  82. }
  83. ++i;
  84. }
  85. nr_days = perf_history.nr_days();
  86. i = 0;
  87. for (auto bw : perf_history.daily_perf()) {
  88. daily_perf[i++] = bw;
  89. }
  90. nr_weeks = perf_history.nr_weeks();
  91. i = 0;
  92. for (auto bw : perf_history.weekly_perf()) {
  93. weekly_perf[i++] = bw;
  94. }
  95. }
  96. void storage_info_t::refresh(IOPerfHistory* perf_history)
  97. {
  98. struct statvfs buf;
  99. if (statvfs(userdata_path.c_str(), &buf) != 0) {
  100. PLOG_TO(SYSTEM, WARNING) << "Failed to get userdata info";
  101. return;
  102. }
  103. userdata_total_kb = buf.f_bsize * buf.f_blocks >> 10;
  104. userdata_free_kb = buf.f_bfree * buf.f_blocks >> 10;
  105. Mutex::Autolock _l(si_mutex);
  106. perf_history->Clear();
  107. perf_history->set_day_start_sec(
  108. duration_cast<chrono::seconds>(day_start_tp.time_since_epoch()).count());
  109. for (const uint32_t& bw : recent_perf) {
  110. perf_history->add_recent_perf(bw);
  111. }
  112. perf_history->set_nr_samples(nr_samples);
  113. for (const uint32_t& bw : daily_perf) {
  114. perf_history->add_daily_perf(bw);
  115. }
  116. perf_history->set_nr_days(nr_days);
  117. for (const uint32_t& bw : weekly_perf) {
  118. perf_history->add_weekly_perf(bw);
  119. }
  120. perf_history->set_nr_weeks(nr_weeks);
  121. }
  122. void storage_info_t::publish()
  123. {
  124. android_log_event_list(EVENTLOGTAG_EMMCINFO)
  125. << version << eol << lifetime_a << lifetime_b
  126. << LOG_ID_EVENTS;
  127. }
  128. void storage_info_t::update_perf_history(uint32_t bw,
  129. const time_point<system_clock>& tp)
  130. {
  131. Mutex::Autolock _l(si_mutex);
  132. if (tp > day_start_tp &&
  133. duration_cast<chrono::seconds>(tp - day_start_tp).count() < DAY_TO_SEC) {
  134. if (nr_samples >= recent_perf.size()) {
  135. recent_perf.push_back(bw);
  136. } else {
  137. recent_perf[nr_samples] = bw;
  138. }
  139. nr_samples++;
  140. return;
  141. }
  142. if (nr_samples < recent_perf.size()) {
  143. recent_perf.erase(recent_perf.begin() + nr_samples, recent_perf.end());
  144. }
  145. uint32_t daily_avg_bw = 0;
  146. if (!recent_perf.empty()) {
  147. daily_avg_bw = accumulate(recent_perf.begin(), recent_perf.end(), 0) / recent_perf.size();
  148. }
  149. day_start_tp = tp - chrono::seconds(duration_cast<chrono::seconds>(
  150. tp.time_since_epoch()).count() % DAY_TO_SEC);
  151. nr_samples = 0;
  152. if (recent_perf.empty())
  153. recent_perf.resize(1);
  154. recent_perf[nr_samples++] = bw;
  155. if (nr_days < WEEK_TO_DAYS) {
  156. daily_perf[nr_days++] = daily_avg_bw;
  157. return;
  158. }
  159. DCHECK(nr_days > 0);
  160. uint32_t week_avg_bw = accumulate(daily_perf.begin(),
  161. daily_perf.begin() + nr_days, 0) / nr_days;
  162. nr_days = 0;
  163. daily_perf[nr_days++] = daily_avg_bw;
  164. if (nr_weeks >= YEAR_TO_WEEKS) {
  165. nr_weeks = 0;
  166. }
  167. weekly_perf[nr_weeks++] = week_avg_bw;
  168. }
  169. vector<int> storage_info_t::get_perf_history()
  170. {
  171. Mutex::Autolock _l(si_mutex);
  172. vector<int> ret(3 + recent_perf.size() + daily_perf.size() + weekly_perf.size());
  173. ret[0] = recent_perf.size();
  174. ret[1] = daily_perf.size();
  175. ret[2] = weekly_perf.size();
  176. int start = 3;
  177. for (size_t i = 0; i < recent_perf.size(); i++) {
  178. int idx = (recent_perf.size() + nr_samples - 1 - i) % recent_perf.size();
  179. ret[start + i] = recent_perf[idx];
  180. }
  181. start += recent_perf.size();
  182. for (size_t i = 0; i < daily_perf.size(); i++) {
  183. int idx = (daily_perf.size() + nr_days - 1 - i) % daily_perf.size();
  184. ret[start + i] = daily_perf[idx];
  185. }
  186. start += daily_perf.size();
  187. for (size_t i = 0; i < weekly_perf.size(); i++) {
  188. int idx = (weekly_perf.size() + nr_weeks - 1 - i) % weekly_perf.size();
  189. ret[start + i] = weekly_perf[idx];
  190. }
  191. return ret;
  192. }
  193. uint32_t storage_info_t::get_recent_perf() {
  194. Mutex::Autolock _l(si_mutex);
  195. if (recent_perf.size() == 0) return 0;
  196. return accumulate(recent_perf.begin(), recent_perf.end(), recent_perf.size() / 2) /
  197. recent_perf.size();
  198. }
  199. void emmc_info_t::report()
  200. {
  201. if (!report_sysfs() && !report_debugfs())
  202. return;
  203. publish();
  204. }
  205. bool emmc_info_t::report_sysfs()
  206. {
  207. string buffer;
  208. uint16_t rev = 0;
  209. if (!ReadFileToString(emmc_sysfs + "rev", &buffer)) {
  210. return false;
  211. }
  212. if (sscanf(buffer.c_str(), "0x%hx", &rev) < 1 ||
  213. rev < 7 || rev > ARRAY_SIZE(emmc_ver_str)) {
  214. return false;
  215. }
  216. version = "emmc ";
  217. version += emmc_ver_str[rev];
  218. if (!ReadFileToString(emmc_sysfs + "pre_eol_info", &buffer)) {
  219. return false;
  220. }
  221. if (sscanf(buffer.c_str(), "%hx", &eol) < 1 || eol == 0) {
  222. return false;
  223. }
  224. if (!ReadFileToString(emmc_sysfs + "life_time", &buffer)) {
  225. return false;
  226. }
  227. if (sscanf(buffer.c_str(), "0x%hx 0x%hx", &lifetime_a, &lifetime_b) < 2 ||
  228. (lifetime_a == 0 && lifetime_b == 0)) {
  229. return false;
  230. }
  231. return true;
  232. }
  233. namespace {
  234. const size_t EXT_CSD_FILE_MIN_SIZE = 1024;
  235. /* 2 characters in string for each byte */
  236. const size_t EXT_CSD_REV_IDX = 192 * 2;
  237. const size_t EXT_PRE_EOL_INFO_IDX = 267 * 2;
  238. const size_t EXT_DEVICE_LIFE_TIME_EST_A_IDX = 268 * 2;
  239. const size_t EXT_DEVICE_LIFE_TIME_EST_B_IDX = 269 * 2;
  240. } // namespace
  241. bool emmc_info_t::report_debugfs()
  242. {
  243. string buffer;
  244. uint16_t rev = 0;
  245. if (!ReadFileToString(emmc_debugfs, &buffer) ||
  246. buffer.length() < (size_t)EXT_CSD_FILE_MIN_SIZE) {
  247. return false;
  248. }
  249. string str = buffer.substr(EXT_CSD_REV_IDX, 2);
  250. if (!ParseUint(str, &rev) ||
  251. rev < 7 || rev > ARRAY_SIZE(emmc_ver_str)) {
  252. return false;
  253. }
  254. version = "emmc ";
  255. version += emmc_ver_str[rev];
  256. str = buffer.substr(EXT_PRE_EOL_INFO_IDX, 2);
  257. if (!ParseUint(str, &eol)) {
  258. return false;
  259. }
  260. str = buffer.substr(EXT_DEVICE_LIFE_TIME_EST_A_IDX, 2);
  261. if (!ParseUint(str, &lifetime_a)) {
  262. return false;
  263. }
  264. str = buffer.substr(EXT_DEVICE_LIFE_TIME_EST_B_IDX, 2);
  265. if (!ParseUint(str, &lifetime_b)) {
  266. return false;
  267. }
  268. return true;
  269. }
  270. void ufs_info_t::report()
  271. {
  272. string buffer;
  273. if (!ReadFileToString(health_file, &buffer)) {
  274. return;
  275. }
  276. vector<string> lines = Split(buffer, "\n");
  277. if (lines.empty()) {
  278. return;
  279. }
  280. char rev[8];
  281. if (sscanf(lines[0].c_str(), "ufs version: 0x%7s\n", rev) < 1) {
  282. return;
  283. }
  284. version = "ufs " + string(rev);
  285. for (size_t i = 1; i < lines.size(); i++) {
  286. char token[32];
  287. uint16_t val;
  288. int ret;
  289. if ((ret = sscanf(lines[i].c_str(),
  290. "Health Descriptor[Byte offset 0x%*d]: %31s = 0x%hx",
  291. token, &val)) < 2) {
  292. continue;
  293. }
  294. if (string(token) == "bPreEOLInfo") {
  295. eol = val;
  296. } else if (string(token) == "bDeviceLifeTimeEstA") {
  297. lifetime_a = val;
  298. } else if (string(token) == "bDeviceLifeTimeEstB") {
  299. lifetime_b = val;
  300. }
  301. }
  302. if (eol == 0 || (lifetime_a == 0 && lifetime_b == 0)) {
  303. return;
  304. }
  305. publish();
  306. }
  307. void health_storage_info_t::report() {
  308. auto ret = mHealth->getStorageInfo([this](auto result, const auto& halInfos) {
  309. if (result == Result::NOT_SUPPORTED) {
  310. LOG_TO(SYSTEM, DEBUG) << "getStorageInfo is not supported on health HAL.";
  311. return;
  312. }
  313. if (result != Result::SUCCESS || halInfos.size() == 0) {
  314. LOG_TO(SYSTEM, ERROR) << "getStorageInfo failed with result " << toString(result)
  315. << " and size " << halInfos.size();
  316. return;
  317. }
  318. set_values_from_hal_storage_info(halInfos[0]);
  319. publish();
  320. });
  321. if (!ret.isOk()) {
  322. LOG_TO(SYSTEM, ERROR) << "getStorageInfo failed with " << ret.description();
  323. }
  324. }
  325. void health_storage_info_t::set_values_from_hal_storage_info(const StorageInfo& halInfo) {
  326. eol = halInfo.eol;
  327. lifetime_a = halInfo.lifetimeA;
  328. lifetime_b = halInfo.lifetimeB;
  329. version = halInfo.version;
  330. }