storaged_info.cpp revision b90f1ae1e5d9886dc32b2f653ab2899a0416bd71
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 17#define LOG_TAG "storaged" 18 19#include <stdio.h> 20#include <string.h> 21 22#include <android-base/file.h> 23#include <android-base/parseint.h> 24#include <android-base/logging.h> 25#include <android-base/strings.h> 26#include <log/log_event_list.h> 27 28#include "storaged.h" 29 30using namespace std; 31using namespace android::base; 32 33void report_storage_health() 34{ 35 emmc_info_t mmc; 36 ufs_info_t ufs; 37 38 mmc.report(); 39 ufs.report(); 40} 41 42void storage_info_t::publish() 43{ 44 android_log_event_list(EVENTLOGTAG_EMMCINFO) 45 << version << eol << lifetime_a << lifetime_b 46 << LOG_ID_EVENTS; 47} 48 49bool emmc_info_t::report() 50{ 51 if (!report_sysfs() && !report_debugfs()) 52 return false; 53 54 publish(); 55 return true; 56} 57 58bool emmc_info_t::report_sysfs() 59{ 60 string buffer; 61 uint16_t rev = 0; 62 63 if (!ReadFileToString(emmc_sysfs + "rev", &buffer)) { 64 return false; 65 } 66 67 if (sscanf(buffer.c_str(), "0x%hx", &rev) < 1 || 68 rev < 7 || rev > ARRAY_SIZE(emmc_ver_str)) { 69 return false; 70 } 71 72 version = "emmc "; 73 version += emmc_ver_str[rev]; 74 75 if (!ReadFileToString(emmc_sysfs + "pre_eol_info", &buffer)) { 76 return false; 77 } 78 79 if (sscanf(buffer.c_str(), "%hx", &eol) < 1 || eol == 0) { 80 return false; 81 } 82 83 if (!ReadFileToString(emmc_sysfs + "life_time", &buffer)) { 84 return false; 85 } 86 87 if (sscanf(buffer.c_str(), "0x%hx 0x%hx", &lifetime_a, &lifetime_b) < 2 || 88 (lifetime_a == 0 && lifetime_b == 0)) { 89 return false; 90 } 91 92 return true; 93} 94 95const size_t EXT_CSD_FILE_MIN_SIZE = 1024; 96/* 2 characters in string for each byte */ 97const size_t EXT_CSD_REV_IDX = 192 * 2; 98const size_t EXT_PRE_EOL_INFO_IDX = 267 * 2; 99const size_t EXT_DEVICE_LIFE_TIME_EST_A_IDX = 268 * 2; 100const size_t EXT_DEVICE_LIFE_TIME_EST_B_IDX = 269 * 2; 101 102bool emmc_info_t::report_debugfs() 103{ 104 string buffer; 105 uint16_t rev = 0; 106 107 if (!ReadFileToString(emmc_debugfs, &buffer) || 108 buffer.length() < (size_t)EXT_CSD_FILE_MIN_SIZE) { 109 return false; 110 } 111 112 string str = buffer.substr(EXT_CSD_REV_IDX, 2); 113 if (!ParseUint(str, &rev) || 114 rev < 7 || rev > ARRAY_SIZE(emmc_ver_str)) { 115 return false; 116 } 117 118 version = "emmc "; 119 version += emmc_ver_str[rev]; 120 121 str = buffer.substr(EXT_PRE_EOL_INFO_IDX, 2); 122 if (!ParseUint(str, &eol)) { 123 return false; 124 } 125 126 str = buffer.substr(EXT_DEVICE_LIFE_TIME_EST_A_IDX, 2); 127 if (!ParseUint(str, &lifetime_a)) { 128 return false; 129 } 130 131 str = buffer.substr(EXT_DEVICE_LIFE_TIME_EST_B_IDX, 2); 132 if (!ParseUint(str, &lifetime_b)) { 133 return false; 134 } 135 136 return true; 137} 138 139bool ufs_info_t::report() 140{ 141 string buffer; 142 if (!ReadFileToString(health_file, &buffer)) { 143 return false; 144 } 145 146 vector<string> lines = Split(buffer, "\n"); 147 if (lines.empty()) { 148 return false; 149 } 150 151 char rev[8]; 152 if (sscanf(lines[0].c_str(), "ufs version: 0x%7s\n", rev) < 1) { 153 return false; 154 } 155 156 version = "ufs " + string(rev); 157 158 for (size_t i = 1; i < lines.size(); i++) { 159 char token[32]; 160 uint16_t val; 161 int ret; 162 if ((ret = sscanf(lines[i].c_str(), 163 "Health Descriptor[Byte offset 0x%*d]: %31s = 0x%hx", 164 token, &val)) < 2) { 165 continue; 166 } 167 168 if (string(token) == "bPreEOLInfo") { 169 eol = val; 170 } else if (string(token) == "bDeviceLifeTimeEstA") { 171 lifetime_a = val; 172 } else if (string(token) == "bDeviceLifeTimeEstB") { 173 lifetime_b = val; 174 } 175 } 176 177 if (eol == 0 || (lifetime_a == 0 && lifetime_b == 0)) { 178 return false; 179 } 180 181 publish(); 182 return true; 183} 184 185