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 
is_charger_on(BatteryStatus prop)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 
healthInfoChanged(const HealthInfo & props)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 
init()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 
init_health_service()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 
serviceDied(uint64_t cookie,const wp<::android::hidl::base::V1_0::IBase> & who)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 
report_storage_info()136 void storaged_t::report_storage_info() {
137     storage_info->report();
138 }
139 
140 /* storaged_t */
storaged_t(void)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 
add_user_ce(userid_t user_id)165 void storaged_t::add_user_ce(userid_t user_id) {
166     load_proto(user_id);
167     proto_loaded[user_id] = true;
168 }
169 
remove_user_ce(userid_t user_id)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 
load_proto(userid_t user_id)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 
prepare_proto(userid_t user_id,StoragedProto * proto)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 
flush_proto_data(userid_t user_id,const char * data,ssize_t size)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 
flush_proto(userid_t user_id,StoragedProto * proto)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 
flush_protos(unordered_map<int,StoragedProto> * protos)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 
event(void)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 
event_checked(void)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