blob: 53da6a3dbb70bcce518f22b05810222a781a483f [file] [log] [blame]
ynwang62cb3722016-06-17 14:30:48 -07001/*
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
Jin Qian6df3bc62017-10-18 17:52:14 -070019#include <dirent.h>
ynwang62cb3722016-06-17 14:30:48 -070020#include <stdlib.h>
Jin Qiand691d6e2017-09-28 16:02:22 -070021#include <stdio.h>
ynwang62cb3722016-06-17 14:30:48 -070022#include <time.h>
23#include <unistd.h>
Jin Qiand691d6e2017-09-28 16:02:22 -070024#include <zlib.h>
25
26#include <chrono>
27#include <fstream>
28#include <sstream>
29#include <string>
ynwang62cb3722016-06-17 14:30:48 -070030
Jin Qian6df3bc62017-10-18 17:52:14 -070031#include <android-base/file.h>
ynwang62cb3722016-06-17 14:30:48 -070032#include <android-base/logging.h>
Yifan Hong70c44e72018-01-16 17:50:58 -080033#include <android/hidl/manager/1.0/IServiceManager.h>
Jin Qian5b962c62017-01-30 14:48:38 -080034#include <batteryservice/BatteryServiceConstants.h>
Jin Qian3790f5b2017-01-23 14:38:47 -080035#include <cutils/properties.h>
Yifan Hong70c44e72018-01-16 17:50:58 -080036#include <healthhalutils/HealthHalUtils.h>
Yifan Hongbf2dcb22017-09-27 14:01:30 -070037#include <hidl/HidlTransportSupport.h>
38#include <hwbinder/IPCThreadState.h>
Jin Qianf42d7c82017-01-26 11:20:26 -080039#include <log/log.h>
ynwang62cb3722016-06-17 14:30:48 -070040
41#include <storaged.h>
42#include <storaged_utils.h>
43
Jin Qiand691d6e2017-09-28 16:02:22 -070044using namespace android::base;
45using namespace chrono;
46using namespace google::protobuf::io;
47using namespace storaged_proto;
48
49namespace {
50
Jin Qian6df3bc62017-10-18 17:52:14 -070051/*
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 */
56constexpr int USER_SYSTEM = 0;
Jin Qiand691d6e2017-09-28 16:02:22 -070057
Jin Qian4c23c452017-12-12 18:38:25 -080058constexpr ssize_t benchmark_unit_size = 16 * 1024; // 16KB
59
60constexpr ssize_t min_benchmark_size = 128 * 1024; // 128KB
Jin Qian6df3bc62017-10-18 17:52:14 -070061
62} // namespace
Jin Qiand691d6e2017-09-28 16:02:22 -070063
Jin Qian4c23c452017-12-12 18:38:25 -080064const uint32_t storaged_t::current_version = 4;
ynwang62cb3722016-06-17 14:30:48 -070065
Yifan Hongbf2dcb22017-09-27 14:01:30 -070066using android::hardware::interfacesEqual;
67using android::hardware::Return;
Yifan Hong70c44e72018-01-16 17:50:58 -080068using android::hardware::health::V1_0::BatteryStatus;
Yifan Hong70c44e72018-01-16 17:50:58 -080069using android::hardware::health::V1_0::toString;
70using android::hardware::health::V2_0::get_health_service;
Hridya Valsaraju79d38eb2018-01-17 23:02:56 -080071using android::hardware::health::V2_0::HealthInfo;
Yifan Hong70c44e72018-01-16 17:50:58 -080072using android::hardware::health::V2_0::IHealth;
73using android::hardware::health::V2_0::Result;
Yifan Hongbf2dcb22017-09-27 14:01:30 -070074using android::hidl::manager::V1_0::IServiceManager;
Jin Qian5b962c62017-01-30 14:48:38 -080075
Jin Qian5b962c62017-01-30 14:48:38 -080076
Yifan Hongbf2dcb22017-09-27 14:01:30 -070077inline charger_stat_t is_charger_on(BatteryStatus prop) {
78 return (prop == BatteryStatus::CHARGING || prop == BatteryStatus::FULL) ?
Jin Qian5b962c62017-01-30 14:48:38 -080079 CHARGER_ON : CHARGER_OFF;
80}
81
Yifan Hongbf2dcb22017-09-27 14:01:30 -070082Return<void> storaged_t::healthInfoChanged(const HealthInfo& props) {
Hridya Valsaraju79d38eb2018-01-17 23:02:56 -080083 mUidm.set_charger_state(is_charger_on(props.legacy.batteryStatus));
Yifan Hongbf2dcb22017-09-27 14:01:30 -070084 return android::hardware::Void();
Jin Qian5b962c62017-01-30 14:48:38 -080085}
86
Yifan Hong4a43bdc2018-01-16 17:20:32 -080087void storaged_t::init() {
88 init_health_service();
Yifan Hongc4b46e02018-01-16 15:49:08 -080089 mDsm = std::make_unique<disk_stats_monitor>(health);
Yifan Hong845e35b2018-01-16 16:03:36 -080090 storage_info.reset(storage_info_t::get_storage_info(health));
Yifan Hong4a43bdc2018-01-16 17:20:32 -080091}
92
Yifan Hongbf2dcb22017-09-27 14:01:30 -070093void storaged_t::init_health_service() {
Jin Qian65dea712017-08-29 16:48:20 -070094 if (!mUidm.enabled())
Jin Qianba27df42017-03-28 15:21:20 -070095 return;
96
Yifan Hongbf2dcb22017-09-27 14:01:30 -070097 health = get_health_service();
98 if (health == NULL) {
99 LOG_TO(SYSTEM, WARNING) << "health: failed to find IHealth service";
Jin Qian5b962c62017-01-30 14:48:38 -0800100 return;
101 }
102
Yifan Hongbf2dcb22017-09-27 14:01:30 -0700103 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 }
Jin Qian5b962c62017-01-30 14:48:38 -0800119
Yifan Hongbf2dcb22017-09-27 14:01:30 -0700120 mUidm.init(is_charger_on(status));
Jin Qian5b962c62017-01-30 14:48:38 -0800121 // register listener after init uid_monitor
Yifan Hongbf2dcb22017-09-27 14:01:30 -0700122 health->registerCallback(this);
123 health->linkToDeath(this, 0 /* cookie */);
Jin Qian566e63d2017-03-31 14:26:23 -0700124}
125
Yifan Hongbf2dcb22017-09-27 14:01:30 -0700126void 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();
Jin Qian566e63d2017-03-31 14:26:23 -0700130 exit(1);
131 } else {
132 LOG_TO(SYSTEM, ERROR) << "unknown service died";
133 }
Jin Qian5b962c62017-01-30 14:48:38 -0800134}
135
Jin Qian8847c622017-07-17 15:06:11 -0700136void storaged_t::report_storage_info() {
137 storage_info->report();
138}
139
ynwang62cb3722016-06-17 14:30:48 -0700140/* storaged_t */
Jin Qian6df3bc62017-10-18 17:52:14 -0700141storaged_t::storaged_t(void) {
Jin Qian3790f5b2017-01-23 14:38:47 -0800142 mConfig.periodic_chores_interval_unit =
Jin Qian65dea712017-08-29 16:48:20 -0700143 property_get_int32("ro.storaged.event.interval",
144 DEFAULT_PERIODIC_CHORES_INTERVAL_UNIT);
Jin Qian3790f5b2017-01-23 14:38:47 -0800145
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 =
Jin Qian65dea712017-08-29 16:48:20 -0700150 property_get_int32("ro.storaged.disk_stats_pub",
151 DEFAULT_PERIODIC_CHORES_INTERVAL_DISK_STATS_PUBLISH);
Jin Qian3790f5b2017-01-23 14:38:47 -0800152
Jin Qian5b962c62017-01-30 14:48:38 -0800153 mConfig.periodic_chores_interval_uid_io =
Jin Qian65dea712017-08-29 16:48:20 -0700154 property_get_int32("ro.storaged.uid_io.interval",
155 DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO);
ynwang62cb3722016-06-17 14:30:48 -0700156
Jin Qiand691d6e2017-09-28 16:02:22 -0700157 mConfig.periodic_chores_interval_flush_proto =
158 property_get_int32("ro.storaged.flush_proto.interval",
159 DEFAULT_PERIODIC_CHORES_INTERVAL_FLUSH_PROTO);
160
ynwang62cb3722016-06-17 14:30:48 -0700161 mStarttime = time(NULL);
Jin Qian65dea712017-08-29 16:48:20 -0700162 mTimer = 0;
ynwang62cb3722016-06-17 14:30:48 -0700163}
164
Jin Qian6df3bc62017-10-18 17:52:14 -0700165void storaged_t::add_user_ce(userid_t user_id) {
Mark Salyzynfc8e9872020-11-20 09:30:29 -0800166 Mutex::Autolock _l(proto_lock);
167
Joe Yu3a20da62018-10-31 14:37:42 +0800168 if (!proto_loaded[user_id]) {
169 load_proto(user_id);
170 proto_loaded[user_id] = true;
171 }
Jin Qian6df3bc62017-10-18 17:52:14 -0700172}
Jin Qian65dea712017-08-29 16:48:20 -0700173
Jin Qian6df3bc62017-10-18 17:52:14 -0700174void storaged_t::remove_user_ce(userid_t user_id) {
Mark Salyzynfc8e9872020-11-20 09:30:29 -0800175 Mutex::Autolock _l(proto_lock);
176
Jin Qian94b64ef2017-11-09 15:07:18 -0800177 proto_loaded[user_id] = false;
178 mUidm.clear_user_history(user_id);
Jin Qian6df3bc62017-10-18 17:52:14 -0700179 RemoveFileIfExists(proto_path(user_id), nullptr);
180}
Jin Qiand691d6e2017-09-28 16:02:22 -0700181
Jin Qian94b64ef2017-11-09 15:07:18 -0800182void storaged_t::load_proto(userid_t user_id) {
Jin Qian6df3bc62017-10-18 17:52:14 -0700183 string proto_file = proto_path(user_id);
184 ifstream in(proto_file, ofstream::in | ofstream::binary);
185
186 if (!in.good()) return;
Jin Qiana8533322017-10-13 18:15:34 -0700187
Jin Qiand691d6e2017-09-28 16:02:22 -0700188 stringstream ss;
189 ss << in.rdbuf();
Jin Qian94b64ef2017-11-09 15:07:18 -0800190 StoragedProto proto;
191 proto.ParseFromString(ss.str());
Jin Qiand691d6e2017-09-28 16:02:22 -0700192
Jin Qian4c23c452017-12-12 18:38:25 -0800193 const UidIOUsage& uid_io_usage = proto.uid_io_usage();
194 uint32_t computed_crc = crc32(current_version,
195 reinterpret_cast<const Bytef*>(uid_io_usage.SerializeAsString().c_str()),
196 uid_io_usage.ByteSize());
197 if (proto.crc() != computed_crc) {
Jin Qiand691d6e2017-09-28 16:02:22 -0700198 LOG_TO(SYSTEM, WARNING) << "CRC mismatch in " << proto_file;
Jin Qiana8533322017-10-13 18:15:34 -0700199 return;
Jin Qiand691d6e2017-09-28 16:02:22 -0700200 }
Jin Qiana8533322017-10-13 18:15:34 -0700201
Jin Qian94b64ef2017-11-09 15:07:18 -0800202 mUidm.load_uid_io_proto(proto.uid_io_usage());
Jin Qiana8533322017-10-13 18:15:34 -0700203
Jin Qian6df3bc62017-10-18 17:52:14 -0700204 if (user_id == USER_SYSTEM) {
Jin Qian94b64ef2017-11-09 15:07:18 -0800205 storage_info->load_perf_history_proto(proto.perf_history());
Jin Qian6df3bc62017-10-18 17:52:14 -0700206 }
Jin Qiand691d6e2017-09-28 16:02:22 -0700207}
208
Jin Qian4c23c452017-12-12 18:38:25 -0800209char* storaged_t:: prepare_proto(userid_t user_id, StoragedProto* proto) {
210 proto->set_version(current_version);
Jin Qiana8533322017-10-13 18:15:34 -0700211
Jin Qian4c23c452017-12-12 18:38:25 -0800212 const UidIOUsage& uid_io_usage = proto->uid_io_usage();
213 proto->set_crc(crc32(current_version,
214 reinterpret_cast<const Bytef*>(uid_io_usage.SerializeAsString().c_str()),
215 uid_io_usage.ByteSize()));
216
217 uint32_t pagesize = sysconf(_SC_PAGESIZE);
Jin Qian6df3bc62017-10-18 17:52:14 -0700218 if (user_id == USER_SYSTEM) {
Jin Qian4c23c452017-12-12 18:38:25 -0800219 proto->set_padding("", 1);
220 vector<char> padding;
221 ssize_t size = ROUND_UP(MAX(min_benchmark_size, proto->ByteSize()),
222 pagesize);
223 padding = vector<char>(size - proto->ByteSize(), 0xFD);
224 proto->set_padding(padding.data(), padding.size());
225 while (!IS_ALIGNED(proto->ByteSize(), pagesize)) {
226 padding.push_back(0xFD);
227 proto->set_padding(padding.data(), padding.size());
Jin Qian6df3bc62017-10-18 17:52:14 -0700228 }
Jin Qiand691d6e2017-09-28 16:02:22 -0700229 }
Jin Qian6df3bc62017-10-18 17:52:14 -0700230
Jin Qian4c23c452017-12-12 18:38:25 -0800231 char* data = nullptr;
232 if (posix_memalign(reinterpret_cast<void**>(&data),
233 pagesize, proto->ByteSize())) {
234 PLOG_TO(SYSTEM, ERROR) << "Faied to alloc aligned buffer (size: "
235 << proto->ByteSize() << ")";
236 return data;
237 }
238
239 proto->SerializeToArray(data, proto->ByteSize());
240 return data;
Jin Qian6df3bc62017-10-18 17:52:14 -0700241}
Jin Qiand691d6e2017-09-28 16:02:22 -0700242
Jin Qian4c23c452017-12-12 18:38:25 -0800243void storaged_t::flush_proto_data(userid_t user_id,
244 const char* data, ssize_t size) {
245 string proto_file = proto_path(user_id);
Jin Qian6df3bc62017-10-18 17:52:14 -0700246 string tmp_file = proto_file + "_tmp";
Jin Qiand691d6e2017-09-28 16:02:22 -0700247 unique_fd fd(TEMP_FAILURE_RETRY(open(tmp_file.c_str(),
Jin Qian4c23c452017-12-12 18:38:25 -0800248 O_SYNC | O_CREAT | O_TRUNC | O_WRONLY | O_CLOEXEC |
249 (user_id == USER_SYSTEM ? O_DIRECT : 0),
250 S_IRUSR | S_IWUSR)));
Jin Qiand691d6e2017-09-28 16:02:22 -0700251 if (fd == -1) {
252 PLOG_TO(SYSTEM, ERROR) << "Faied to open tmp file: " << tmp_file;
253 return;
254 }
255
Jin Qian4c23c452017-12-12 18:38:25 -0800256 if (user_id == USER_SYSTEM) {
257 time_point<steady_clock> start, end;
258 uint32_t benchmark_size = 0;
259 uint64_t benchmark_time_ns = 0;
260 ssize_t ret;
261 bool first_write = true;
262
263 while (size > 0) {
264 start = steady_clock::now();
265 ret = write(fd, data, MIN(benchmark_unit_size, size));
266 if (ret <= 0) {
267 PLOG_TO(SYSTEM, ERROR) << "Faied to write tmp file: " << tmp_file;
268 return;
269 }
270 end = steady_clock::now();
271 /*
272 * compute bandwidth after the first write and if write returns
273 * exactly unit size.
274 */
275 if (!first_write && ret == benchmark_unit_size) {
276 benchmark_size += benchmark_unit_size;
277 benchmark_time_ns += duration_cast<nanoseconds>(end - start).count();
278 }
279 size -= ret;
280 data += ret;
281 first_write = false;
282 }
283
284 if (benchmark_size) {
285 int perf = benchmark_size * 1000000LLU / benchmark_time_ns;
286 storage_info->update_perf_history(perf, system_clock::now());
287 }
288 } else {
289 if (!WriteFully(fd, data, size)) {
Jin Qiand691d6e2017-09-28 16:02:22 -0700290 PLOG_TO(SYSTEM, ERROR) << "Faied to write tmp file: " << tmp_file;
291 return;
292 }
Jin Qiand691d6e2017-09-28 16:02:22 -0700293 }
294
295 fd.reset(-1);
Jin Qiand691d6e2017-09-28 16:02:22 -0700296 rename(tmp_file.c_str(), proto_file.c_str());
297}
298
Jin Qian94b64ef2017-11-09 15:07:18 -0800299void storaged_t::flush_proto(userid_t user_id, StoragedProto* proto) {
Jin Qian4c23c452017-12-12 18:38:25 -0800300 unique_ptr<char> proto_data(prepare_proto(user_id, proto));
301 if (proto_data == nullptr) return;
Jin Qian94b64ef2017-11-09 15:07:18 -0800302
Jin Qian4c23c452017-12-12 18:38:25 -0800303 flush_proto_data(user_id, proto_data.get(), proto->ByteSize());
Jin Qian6df3bc62017-10-18 17:52:14 -0700304}
305
Jin Qian94b64ef2017-11-09 15:07:18 -0800306void storaged_t::flush_protos(unordered_map<int, StoragedProto>* protos) {
Mark Salyzynfc8e9872020-11-20 09:30:29 -0800307 Mutex::Autolock _l(proto_lock);
308
Jin Qian94b64ef2017-11-09 15:07:18 -0800309 for (auto& it : *protos) {
Jin Qian6df3bc62017-10-18 17:52:14 -0700310 /*
Jin Qian94b64ef2017-11-09 15:07:18 -0800311 * Don't flush proto if we haven't attempted to load it from file.
Jin Qian6df3bc62017-10-18 17:52:14 -0700312 */
Jin Qian94b64ef2017-11-09 15:07:18 -0800313 if (proto_loaded[it.first]) {
314 flush_proto(it.first, &it.second);
Jin Qian6df3bc62017-10-18 17:52:14 -0700315 }
Jin Qian6df3bc62017-10-18 17:52:14 -0700316 }
317}
318
319void storaged_t::event(void) {
Jin Qian94b64ef2017-11-09 15:07:18 -0800320 unordered_map<int, StoragedProto> protos;
321
Yifan Hongc4b46e02018-01-16 15:49:08 -0800322 if (mDsm->enabled()) {
323 mDsm->update();
Jin Qian65dea712017-08-29 16:48:20 -0700324 if (!(mTimer % mConfig.periodic_chores_interval_disk_stats_publish)) {
Yifan Hongc4b46e02018-01-16 15:49:08 -0800325 mDsm->publish();
ynwang62cb3722016-06-17 14:30:48 -0700326 }
327 }
328
Jin Qiana8533322017-10-13 18:15:34 -0700329 if (!(mTimer % mConfig.periodic_chores_interval_uid_io)) {
Jin Qian6df3bc62017-10-18 17:52:14 -0700330 mUidm.report(&protos);
Jin Qiand691d6e2017-09-28 16:02:22 -0700331 }
332
Jin Qian6df3bc62017-10-18 17:52:14 -0700333 if (storage_info) {
Jin Qian6df3bc62017-10-18 17:52:14 -0700334 storage_info->refresh(protos[USER_SYSTEM].mutable_perf_history());
335 }
336
Jin Qiand691d6e2017-09-28 16:02:22 -0700337 if (!(mTimer % mConfig.periodic_chores_interval_flush_proto)) {
Jin Qian94b64ef2017-11-09 15:07:18 -0800338 flush_protos(&protos);
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800339 }
340
ynwang62cb3722016-06-17 14:30:48 -0700341 mTimer += mConfig.periodic_chores_interval_unit;
ynwangaf49d972016-06-17 14:30:48 -0700342}
Jin Qian3790f5b2017-01-23 14:38:47 -0800343
344void storaged_t::event_checked(void) {
345 struct timespec start_ts, end_ts;
346 bool check_time = true;
347
348 if (mConfig.event_time_check_usec &&
349 clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start_ts) < 0) {
350 check_time = false;
Jin Qianf42d7c82017-01-26 11:20:26 -0800351 static time_t state_a;
352 IF_ALOG_RATELIMIT_LOCAL(300, &state_a) {
353 PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed";
354 }
Jin Qian3790f5b2017-01-23 14:38:47 -0800355 }
356
357 event();
358
Jin Qianf42d7c82017-01-26 11:20:26 -0800359 if (mConfig.event_time_check_usec && check_time) {
Jin Qian3790f5b2017-01-23 14:38:47 -0800360 if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end_ts) < 0) {
Jin Qianf42d7c82017-01-26 11:20:26 -0800361 static time_t state_b;
362 IF_ALOG_RATELIMIT_LOCAL(300, &state_b) {
363 PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed";
364 }
Jin Qian3790f5b2017-01-23 14:38:47 -0800365 return;
366 }
367 int64_t cost = (end_ts.tv_sec - start_ts.tv_sec) * SEC_TO_USEC +
368 (end_ts.tv_nsec - start_ts.tv_nsec) / USEC_TO_NSEC;
369 if (cost > mConfig.event_time_check_usec) {
370 LOG_TO(SYSTEM, ERROR)
371 << "event loop spent " << cost << " usec, threshold "
372 << mConfig.event_time_check_usec << " usec";
373 }
374 }
375}