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