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 <dirent.h> 20 #include <stdlib.h> 21 #include <stdio.h> 22 #include <time.h> 23 #include <unistd.h> 24 #include <zlib.h> 25 26 #include <chrono> 27 #include <fstream> 28 #include <sstream> 29 #include <string> 30 31 #include <android-base/file.h> 32 #include <android-base/logging.h> 33 #include <android/hidl/manager/1.0/IServiceManager.h> 34 #include <batteryservice/BatteryServiceConstants.h> 35 #include <cutils/properties.h> 36 #include <healthhalutils/HealthHalUtils.h> 37 #include <hidl/HidlTransportSupport.h> 38 #include <hwbinder/IPCThreadState.h> 39 #include <log/log.h> 40 41 #include <storaged.h> 42 #include <storaged_utils.h> 43 44 using namespace android::base; 45 using namespace chrono; 46 using namespace google::protobuf::io; 47 using namespace storaged_proto; 48 49 namespace { 50 51 /* 52 * The system user is the initial user that is implicitly created on first boot 53 * and hosts most of the system services. Keep this in sync with 54 * frameworks/base/core/java/android/os/UserManager.java 55 */ 56 constexpr int USER_SYSTEM = 0; 57 58 constexpr ssize_t benchmark_unit_size = 16 * 1024; // 16KB 59 60 constexpr ssize_t min_benchmark_size = 128 * 1024; // 128KB 61 62 } // namespace 63 64 const uint32_t storaged_t::current_version = 4; 65 66 using android::hardware::interfacesEqual; 67 using android::hardware::Return; 68 using android::hardware::health::V1_0::BatteryStatus; 69 using android::hardware::health::V1_0::toString; 70 using android::hardware::health::V2_0::get_health_service; 71 using android::hardware::health::V2_0::HealthInfo; 72 using android::hardware::health::V2_0::IHealth; 73 using android::hardware::health::V2_0::Result; 74 using android::hidl::manager::V1_0::IServiceManager; 75 76 77 inline charger_stat_t is_charger_on(BatteryStatus prop) { 78 return (prop == BatteryStatus::CHARGING || prop == BatteryStatus::FULL) ? 79 CHARGER_ON : CHARGER_OFF; 80 } 81 82 Return<void> storaged_t::healthInfoChanged(const HealthInfo& props) { 83 mUidm.set_charger_state(is_charger_on(props.legacy.batteryStatus)); 84 return android::hardware::Void(); 85 } 86 87 void storaged_t::init() { 88 init_health_service(); 89 mDsm = std::make_unique<disk_stats_monitor>(health); 90 storage_info.reset(storage_info_t::get_storage_info(health)); 91 } 92 93 void storaged_t::init_health_service() { 94 if (!mUidm.enabled()) 95 return; 96 97 health = get_health_service(); 98 if (health == NULL) { 99 LOG_TO(SYSTEM, WARNING) << "health: failed to find IHealth service"; 100 return; 101 } 102 103 BatteryStatus status = BatteryStatus::UNKNOWN; 104 auto ret = health->getChargeStatus([&](Result r, BatteryStatus v) { 105 if (r != Result::SUCCESS) { 106 LOG_TO(SYSTEM, WARNING) 107 << "health: cannot get battery status " << toString(r); 108 return; 109 } 110 if (v == BatteryStatus::UNKNOWN) { 111 LOG_TO(SYSTEM, WARNING) << "health: invalid battery status"; 112 } 113 status = v; 114 }); 115 if (!ret.isOk()) { 116 LOG_TO(SYSTEM, WARNING) << "health: get charge status transaction error " 117 << ret.description(); 118 } 119 120 mUidm.init(is_charger_on(status)); 121 // register listener after init uid_monitor 122 health->registerCallback(this); 123 health->linkToDeath(this, 0 /* cookie */); 124 } 125 126 void storaged_t::serviceDied(uint64_t cookie, const wp<::android::hidl::base::V1_0::IBase>& who) { 127 if (health != NULL && interfacesEqual(health, who.promote())) { 128 LOG_TO(SYSTEM, ERROR) << "health service died, exiting"; 129 android::hardware::IPCThreadState::self()->stopProcess(); 130 exit(1); 131 } else { 132 LOG_TO(SYSTEM, ERROR) << "unknown service died"; 133 } 134 } 135 136 void storaged_t::report_storage_info() { 137 storage_info->report(); 138 } 139 140 /* storaged_t */ 141 storaged_t::storaged_t(void) { 142 mConfig.periodic_chores_interval_unit = 143 property_get_int32("ro.storaged.event.interval", 144 DEFAULT_PERIODIC_CHORES_INTERVAL_UNIT); 145 146 mConfig.event_time_check_usec = 147 property_get_int32("ro.storaged.event.perf_check", 0); 148 149 mConfig.periodic_chores_interval_disk_stats_publish = 150 property_get_int32("ro.storaged.disk_stats_pub", 151 DEFAULT_PERIODIC_CHORES_INTERVAL_DISK_STATS_PUBLISH); 152 153 mConfig.periodic_chores_interval_uid_io = 154 property_get_int32("ro.storaged.uid_io.interval", 155 DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO); 156 157 mConfig.periodic_chores_interval_flush_proto = 158 property_get_int32("ro.storaged.flush_proto.interval", 159 DEFAULT_PERIODIC_CHORES_INTERVAL_FLUSH_PROTO); 160 161 mStarttime = time(NULL); 162 mTimer = 0; 163 } 164 165 void storaged_t::add_user_ce(userid_t user_id) { 166 load_proto(user_id); 167 proto_loaded[user_id] = true; 168 } 169 170 void storaged_t::remove_user_ce(userid_t user_id) { 171 proto_loaded[user_id] = false; 172 mUidm.clear_user_history(user_id); 173 RemoveFileIfExists(proto_path(user_id), nullptr); 174 } 175 176 void storaged_t::load_proto(userid_t user_id) { 177 string proto_file = proto_path(user_id); 178 ifstream in(proto_file, ofstream::in | ofstream::binary); 179 180 if (!in.good()) return; 181 182 stringstream ss; 183 ss << in.rdbuf(); 184 StoragedProto proto; 185 proto.ParseFromString(ss.str()); 186 187 const UidIOUsage& uid_io_usage = proto.uid_io_usage(); 188 uint32_t computed_crc = crc32(current_version, 189 reinterpret_cast<const Bytef*>(uid_io_usage.SerializeAsString().c_str()), 190 uid_io_usage.ByteSize()); 191 if (proto.crc() != computed_crc) { 192 LOG_TO(SYSTEM, WARNING) << "CRC mismatch in " << proto_file; 193 return; 194 } 195 196 mUidm.load_uid_io_proto(proto.uid_io_usage()); 197 198 if (user_id == USER_SYSTEM) { 199 storage_info->load_perf_history_proto(proto.perf_history()); 200 } 201 } 202 203 char* storaged_t:: prepare_proto(userid_t user_id, StoragedProto* proto) { 204 proto->set_version(current_version); 205 206 const UidIOUsage& uid_io_usage = proto->uid_io_usage(); 207 proto->set_crc(crc32(current_version, 208 reinterpret_cast<const Bytef*>(uid_io_usage.SerializeAsString().c_str()), 209 uid_io_usage.ByteSize())); 210 211 uint32_t pagesize = sysconf(_SC_PAGESIZE); 212 if (user_id == USER_SYSTEM) { 213 proto->set_padding("", 1); 214 vector<char> padding; 215 ssize_t size = ROUND_UP(MAX(min_benchmark_size, proto->ByteSize()), 216 pagesize); 217 padding = vector<char>(size - proto->ByteSize(), 0xFD); 218 proto->set_padding(padding.data(), padding.size()); 219 while (!IS_ALIGNED(proto->ByteSize(), pagesize)) { 220 padding.push_back(0xFD); 221 proto->set_padding(padding.data(), padding.size()); 222 } 223 } 224 225 char* data = nullptr; 226 if (posix_memalign(reinterpret_cast<void**>(&data), 227 pagesize, proto->ByteSize())) { 228 PLOG_TO(SYSTEM, ERROR) << "Faied to alloc aligned buffer (size: " 229 << proto->ByteSize() << ")"; 230 return data; 231 } 232 233 proto->SerializeToArray(data, proto->ByteSize()); 234 return data; 235 } 236 237 void storaged_t::flush_proto_data(userid_t user_id, 238 const char* data, ssize_t size) { 239 string proto_file = proto_path(user_id); 240 string tmp_file = proto_file + "_tmp"; 241 unique_fd fd(TEMP_FAILURE_RETRY(open(tmp_file.c_str(), 242 O_SYNC | O_CREAT | O_TRUNC | O_WRONLY | O_CLOEXEC | 243 (user_id == USER_SYSTEM ? O_DIRECT : 0), 244 S_IRUSR | S_IWUSR))); 245 if (fd == -1) { 246 PLOG_TO(SYSTEM, ERROR) << "Faied to open tmp file: " << tmp_file; 247 return; 248 } 249 250 if (user_id == USER_SYSTEM) { 251 time_point<steady_clock> start, end; 252 uint32_t benchmark_size = 0; 253 uint64_t benchmark_time_ns = 0; 254 ssize_t ret; 255 bool first_write = true; 256 257 while (size > 0) { 258 start = steady_clock::now(); 259 ret = write(fd, data, MIN(benchmark_unit_size, size)); 260 if (ret <= 0) { 261 PLOG_TO(SYSTEM, ERROR) << "Faied to write tmp file: " << tmp_file; 262 return; 263 } 264 end = steady_clock::now(); 265 /* 266 * compute bandwidth after the first write and if write returns 267 * exactly unit size. 268 */ 269 if (!first_write && ret == benchmark_unit_size) { 270 benchmark_size += benchmark_unit_size; 271 benchmark_time_ns += duration_cast<nanoseconds>(end - start).count(); 272 } 273 size -= ret; 274 data += ret; 275 first_write = false; 276 } 277 278 if (benchmark_size) { 279 int perf = benchmark_size * 1000000LLU / benchmark_time_ns; 280 storage_info->update_perf_history(perf, system_clock::now()); 281 } 282 } else { 283 if (!WriteFully(fd, data, size)) { 284 PLOG_TO(SYSTEM, ERROR) << "Faied to write tmp file: " << tmp_file; 285 return; 286 } 287 } 288 289 fd.reset(-1); 290 rename(tmp_file.c_str(), proto_file.c_str()); 291 } 292 293 void storaged_t::flush_proto(userid_t user_id, StoragedProto* proto) { 294 unique_ptr<char> proto_data(prepare_proto(user_id, proto)); 295 if (proto_data == nullptr) return; 296 297 flush_proto_data(user_id, proto_data.get(), proto->ByteSize()); 298 } 299 300 void storaged_t::flush_protos(unordered_map<int, StoragedProto>* protos) { 301 for (auto& it : *protos) { 302 /* 303 * Don't flush proto if we haven't attempted to load it from file. 304 */ 305 if (proto_loaded[it.first]) { 306 flush_proto(it.first, &it.second); 307 } 308 } 309 } 310 311 void storaged_t::event(void) { 312 unordered_map<int, StoragedProto> protos; 313 314 if (mDsm->enabled()) { 315 mDsm->update(); 316 if (!(mTimer % mConfig.periodic_chores_interval_disk_stats_publish)) { 317 mDsm->publish(); 318 } 319 } 320 321 if (!(mTimer % mConfig.periodic_chores_interval_uid_io)) { 322 mUidm.report(&protos); 323 } 324 325 if (storage_info) { 326 storage_info->refresh(protos[USER_SYSTEM].mutable_perf_history()); 327 } 328 329 if (!(mTimer % mConfig.periodic_chores_interval_flush_proto)) { 330 flush_protos(&protos); 331 } 332 333 mTimer += mConfig.periodic_chores_interval_unit; 334 } 335 336 void storaged_t::event_checked(void) { 337 struct timespec start_ts, end_ts; 338 bool check_time = true; 339 340 if (mConfig.event_time_check_usec && 341 clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start_ts) < 0) { 342 check_time = false; 343 static time_t state_a; 344 IF_ALOG_RATELIMIT_LOCAL(300, &state_a) { 345 PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed"; 346 } 347 } 348 349 event(); 350 351 if (mConfig.event_time_check_usec && check_time) { 352 if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end_ts) < 0) { 353 static time_t state_b; 354 IF_ALOG_RATELIMIT_LOCAL(300, &state_b) { 355 PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed"; 356 } 357 return; 358 } 359 int64_t cost = (end_ts.tv_sec - start_ts.tv_sec) * SEC_TO_USEC + 360 (end_ts.tv_nsec - start_ts.tv_nsec) / USEC_TO_NSEC; 361 if (cost > mConfig.event_time_check_usec) { 362 LOG_TO(SYSTEM, ERROR) 363 << "event loop spent " << cost << " usec, threshold " 364 << mConfig.event_time_check_usec << " usec"; 365 } 366 } 367 } 368