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