blob: 66a9e355fe9227603a50aa986b34b175dce56b80 [file] [log] [blame]
Jin Qianbcd6e3b2016-12-28 15:43:51 -08001/*
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 <stdint.h>
Jin Qianebf031b2017-08-14 16:41:24 -070020#include <stdio.h>
Jin Qianbcd6e3b2016-12-28 15:43:51 -080021#include <time.h>
Jin Qianebf031b2017-08-14 16:41:24 -070022#include <zlib.h>
Jin Qianbcd6e3b2016-12-28 15:43:51 -080023
Jin Qianebf031b2017-08-14 16:41:24 -070024#include <fstream>
Jin Qianbcd6e3b2016-12-28 15:43:51 -080025#include <string>
Jin Qianbcd6e3b2016-12-28 15:43:51 -080026#include <unordered_map>
27
Jin Qian2d7bcce2017-07-28 18:45:59 -070028#include <android/content/pm/IPackageManagerNative.h>
Jin Qianbcd6e3b2016-12-28 15:43:51 -080029#include <android-base/file.h>
30#include <android-base/logging.h>
31#include <android-base/macros.h>
Jin Qian9b1aeae2017-03-14 11:20:02 -070032#include <android-base/parseint.h>
Jin Qiane83a6102017-03-02 16:16:54 -080033#include <android-base/strings.h>
Jin Qianbcd6e3b2016-12-28 15:43:51 -080034#include <android-base/stringprintf.h>
Jin Qian2d7bcce2017-07-28 18:45:59 -070035#include <binder/IServiceManager.h>
Jin Qianbcd6e3b2016-12-28 15:43:51 -080036#include <log/log_event_list.h>
Jin Qianbcd6e3b2016-12-28 15:43:51 -080037
38#include "storaged.h"
39#include "storaged_uid_monitor.h"
Jin Qianebf031b2017-08-14 16:41:24 -070040#include "system/core/storaged/storaged.pb.h"
Jin Qianbcd6e3b2016-12-28 15:43:51 -080041
Jin Qianbcd6e3b2016-12-28 15:43:51 -080042using namespace android;
43using namespace android::base;
Jin Qian2d7bcce2017-07-28 18:45:59 -070044using namespace android::content::pm;
Jin Qianebf031b2017-08-14 16:41:24 -070045using namespace google::protobuf::io;
46using namespace storaged_proto;
Jin Qianbcd6e3b2016-12-28 15:43:51 -080047
Jin Qian65dea712017-08-29 16:48:20 -070048namespace {
49
50bool refresh_uid_names;
51const uint32_t crc_init = 0x5108A4ED; /* STORAGED */
52const char* UID_IO_STATS_PATH = "/proc/uid_io/stats";
53
54} // namepsace
Jin Qianebf031b2017-08-14 16:41:24 -070055
56const std::string uid_monitor::io_history_proto_file =
Jin Qian65dea712017-08-29 16:48:20 -070057"/data/misc/storaged/io_history.proto";
Jin Qianbcd6e3b2016-12-28 15:43:51 -080058
Jin Qian5b962c62017-01-30 14:48:38 -080059std::unordered_map<uint32_t, struct uid_info> uid_monitor::get_uid_io_stats()
Jin Qianbcd6e3b2016-12-28 15:43:51 -080060{
Jin Qian5b962c62017-01-30 14:48:38 -080061 std::unique_ptr<lock_t> lock(new lock_t(&um_lock));
62 return get_uid_io_stats_locked();
63};
Jin Qianbcd6e3b2016-12-28 15:43:51 -080064
Yang Jin3906c892017-06-22 15:18:21 -070065/* return true on parse success and false on failure */
66bool uid_info::parse_uid_io_stats(std::string&& s)
67{
68 std::vector<std::string> fields = Split(s, " ");
69 if (fields.size() < 11 ||
70 !ParseUint(fields[0], &uid) ||
71 !ParseUint(fields[1], &io[FOREGROUND].rchar) ||
72 !ParseUint(fields[2], &io[FOREGROUND].wchar) ||
73 !ParseUint(fields[3], &io[FOREGROUND].read_bytes) ||
74 !ParseUint(fields[4], &io[FOREGROUND].write_bytes) ||
75 !ParseUint(fields[5], &io[BACKGROUND].rchar) ||
76 !ParseUint(fields[6], &io[BACKGROUND].wchar) ||
77 !ParseUint(fields[7], &io[BACKGROUND].read_bytes) ||
78 !ParseUint(fields[8], &io[BACKGROUND].write_bytes) ||
79 !ParseUint(fields[9], &io[FOREGROUND].fsync) ||
80 !ParseUint(fields[10], &io[BACKGROUND].fsync)) {
Jin Qian0e026872017-08-29 11:42:06 -070081 LOG_TO(SYSTEM, WARNING) << "Invalid uid I/O stats: \""
Yang Jin3906c892017-06-22 15:18:21 -070082 << s << "\"";
83 return false;
84 }
85 return true;
86}
87
88/* return true on parse success and false on failure */
89bool task_info::parse_task_io_stats(std::string&& s)
90{
91 std::vector<std::string> fields = Split(s, ",");
Jin Qian0e026872017-08-29 11:42:06 -070092 size_t size = fields.size();
93 if (size < 13 ||
94 !ParseInt(fields[size - 11], &pid) ||
95 !ParseUint(fields[size - 10], &io[FOREGROUND].rchar) ||
96 !ParseUint(fields[size - 9], &io[FOREGROUND].wchar) ||
97 !ParseUint(fields[size - 8], &io[FOREGROUND].read_bytes) ||
98 !ParseUint(fields[size - 7], &io[FOREGROUND].write_bytes) ||
99 !ParseUint(fields[size - 6], &io[BACKGROUND].rchar) ||
100 !ParseUint(fields[size - 5], &io[BACKGROUND].wchar) ||
101 !ParseUint(fields[size - 4], &io[BACKGROUND].read_bytes) ||
102 !ParseUint(fields[size - 3], &io[BACKGROUND].write_bytes) ||
103 !ParseUint(fields[size - 2], &io[FOREGROUND].fsync) ||
104 !ParseUint(fields[size - 1], &io[BACKGROUND].fsync)) {
105 LOG_TO(SYSTEM, WARNING) << "Invalid task I/O stats: \""
Yang Jin3906c892017-06-22 15:18:21 -0700106 << s << "\"";
107 return false;
108 }
Jin Qian0e026872017-08-29 11:42:06 -0700109 comm = Join(std::vector<std::string>(
110 fields.begin() + 1, fields.end() - 11), ',');
Yang Jin3906c892017-06-22 15:18:21 -0700111 return true;
112}
113
114bool io_usage::is_zero() const
115{
116 for (int i = 0; i < IO_TYPES; i++) {
117 for (int j = 0; j < UID_STATS; j++) {
118 for (int k = 0; k < CHARGER_STATS; k++) {
119 if (bytes[i][j][k])
120 return false;
121 }
122 }
123 }
124 return true;
125}
126
Jin Qian65dea712017-08-29 16:48:20 -0700127namespace {
128
129void get_uid_names(const vector<int>& uids, const vector<std::string*>& uid_names)
Jin Qian2d7bcce2017-07-28 18:45:59 -0700130{
131 sp<IServiceManager> sm = defaultServiceManager();
132 if (sm == NULL) {
133 LOG_TO(SYSTEM, ERROR) << "defaultServiceManager failed";
134 return;
135 }
136
137 sp<IBinder> binder = sm->getService(String16("package_native"));
138 if (binder == NULL) {
139 LOG_TO(SYSTEM, ERROR) << "getService package_native failed";
140 return;
141 }
142
143 sp<IPackageManagerNative> package_mgr = interface_cast<IPackageManagerNative>(binder);
144 std::vector<std::string> names;
145 binder::Status status = package_mgr->getNamesForUids(uids, &names);
146 if (!status.isOk()) {
147 LOG_TO(SYSTEM, ERROR) << "package_native::getNamesForUids failed: "
148 << status.exceptionMessage();
149 return;
150 }
151
152 for (uint32_t i = 0; i < uid_names.size(); i++) {
153 if (!names[i].empty()) {
154 *uid_names[i] = names[i];
155 }
156 }
157
158 refresh_uid_names = false;
159}
160
Jin Qian65dea712017-08-29 16:48:20 -0700161} // namespace
162
Jin Qian5b962c62017-01-30 14:48:38 -0800163std::unordered_map<uint32_t, struct uid_info> uid_monitor::get_uid_io_stats_locked()
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800164{
Jin Qian5b962c62017-01-30 14:48:38 -0800165 std::unordered_map<uint32_t, struct uid_info> uid_io_stats;
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800166 std::string buffer;
Jin Qian9b1aeae2017-03-14 11:20:02 -0700167 if (!ReadFileToString(UID_IO_STATS_PATH, &buffer)) {
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800168 PLOG_TO(SYSTEM, ERROR) << UID_IO_STATS_PATH << ": ReadFileToString failed";
Jin Qian5b962c62017-01-30 14:48:38 -0800169 return uid_io_stats;
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800170 }
171
Yang Jin3906c892017-06-22 15:18:21 -0700172 std::vector<std::string> io_stats = Split(std::move(buffer), "\n");
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800173 struct uid_info u;
Jin Qian2d7bcce2017-07-28 18:45:59 -0700174 vector<int> uids;
175 vector<std::string*> uid_names;
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800176
Jin Qiane83a6102017-03-02 16:16:54 -0800177 for (uint32_t i = 0; i < io_stats.size(); i++) {
178 if (io_stats[i].empty()) {
179 continue;
180 }
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800181
Yang Jin3906c892017-06-22 15:18:21 -0700182 if (io_stats[i].compare(0, 4, "task")) {
183 if (!u.parse_uid_io_stats(std::move(io_stats[i])))
184 continue;
Yang Jin3906c892017-06-22 15:18:21 -0700185 uid_io_stats[u.uid] = u;
Jin Qian2d7bcce2017-07-28 18:45:59 -0700186 uid_io_stats[u.uid].name = std::to_string(u.uid);
187 uids.push_back(u.uid);
188 uid_names.push_back(&uid_io_stats[u.uid].name);
189 if (last_uid_io_stats.find(u.uid) == last_uid_io_stats.end()) {
190 refresh_uid_names = true;
191 } else {
192 uid_io_stats[u.uid].name = last_uid_io_stats[u.uid].name;
193 }
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800194 } else {
Yang Jin3906c892017-06-22 15:18:21 -0700195 struct task_info t;
196 if (!t.parse_task_io_stats(std::move(io_stats[i])))
197 continue;
198 uid_io_stats[u.uid].tasks[t.pid] = t;
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800199 }
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800200 }
201
Jin Qian2d7bcce2017-07-28 18:45:59 -0700202 if (!uids.empty() && refresh_uid_names) {
203 get_uid_names(uids, uid_names);
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800204 }
205
Jin Qian5b962c62017-01-30 14:48:38 -0800206 return uid_io_stats;
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800207}
208
Jin Qian65dea712017-08-29 16:48:20 -0700209namespace {
Jin Qiana2e5bd12017-01-24 16:23:13 -0800210
Jin Qian65dea712017-08-29 16:48:20 -0700211const int MAX_UID_RECORDS_SIZE = 1000 * 48; // 1000 uids in 48 hours
212
213inline size_t history_size(
Jin Qianebf031b2017-08-14 16:41:24 -0700214 const std::map<uint64_t, struct uid_records>& history)
Jin Qiana2e5bd12017-01-24 16:23:13 -0800215{
Jin Qianebf031b2017-08-14 16:41:24 -0700216 size_t count = 0;
217 for (auto const& it : history) {
Jin Qian81577752017-02-21 12:09:39 -0800218 count += it.second.entries.size();
Jin Qian5b962c62017-01-30 14:48:38 -0800219 }
220 return count;
Jin Qiana2e5bd12017-01-24 16:23:13 -0800221}
222
Jin Qian65dea712017-08-29 16:48:20 -0700223} // namespace
224
Jin Qian5b962c62017-01-30 14:48:38 -0800225void uid_monitor::add_records_locked(uint64_t curr_ts)
Jin Qiana2e5bd12017-01-24 16:23:13 -0800226{
Jin Qian5b962c62017-01-30 14:48:38 -0800227 // remove records more than 5 days old
228 if (curr_ts > 5 * DAY_TO_SEC) {
Jin Qianebf031b2017-08-14 16:41:24 -0700229 auto it = io_history.lower_bound(curr_ts - 5 * DAY_TO_SEC);
230 io_history.erase(io_history.begin(), it);
Jin Qian9cdfdd32017-01-31 17:33:20 -0800231 }
232
Jin Qian81577752017-02-21 12:09:39 -0800233 struct uid_records new_records;
Jin Qian5b962c62017-01-30 14:48:38 -0800234 for (const auto& p : curr_io_stats) {
235 struct uid_record record = {};
236 record.name = p.first;
Yang Jin3906c892017-06-22 15:18:21 -0700237 if (!p.second.uid_ios.is_zero()) {
238 record.ios.uid_ios = p.second.uid_ios;
239 for (const auto& p_task : p.second.task_ios) {
240 if (!p_task.second.is_zero())
241 record.ios.task_ios[p_task.first] = p_task.second;
242 }
Jin Qian81577752017-02-21 12:09:39 -0800243 new_records.entries.push_back(record);
Jin Qian5b962c62017-01-30 14:48:38 -0800244 }
Jin Qian9cdfdd32017-01-31 17:33:20 -0800245 }
Jin Qian9cdfdd32017-01-31 17:33:20 -0800246
Jin Qian5b962c62017-01-30 14:48:38 -0800247 curr_io_stats.clear();
Jin Qian81577752017-02-21 12:09:39 -0800248 new_records.start_ts = start_ts;
249 start_ts = curr_ts;
Jin Qian9cdfdd32017-01-31 17:33:20 -0800250
Jin Qian81577752017-02-21 12:09:39 -0800251 if (new_records.entries.empty())
Jin Qian5b962c62017-01-30 14:48:38 -0800252 return;
253
254 // make some room for new records
Jin Qianebf031b2017-08-14 16:41:24 -0700255 ssize_t overflow = history_size(io_history) +
Jin Qian81577752017-02-21 12:09:39 -0800256 new_records.entries.size() - MAX_UID_RECORDS_SIZE;
Jin Qianebf031b2017-08-14 16:41:24 -0700257 while (overflow > 0 && io_history.size() > 0) {
258 auto del_it = io_history.begin();
Jin Qian81577752017-02-21 12:09:39 -0800259 overflow -= del_it->second.entries.size();
Jin Qianebf031b2017-08-14 16:41:24 -0700260 io_history.erase(io_history.begin());
Jin Qian5b962c62017-01-30 14:48:38 -0800261 }
262
Jin Qianebf031b2017-08-14 16:41:24 -0700263 io_history[curr_ts] = new_records;
Jin Qian5b962c62017-01-30 14:48:38 -0800264}
265
Jin Qian81577752017-02-21 12:09:39 -0800266std::map<uint64_t, struct uid_records> uid_monitor::dump(
Jin Qiandd41d6b2017-02-10 17:23:16 -0800267 double hours, uint64_t threshold, bool force_report)
Jin Qian5b962c62017-01-30 14:48:38 -0800268{
Jin Qian1275b1b2017-02-06 14:02:50 -0800269 if (force_report) {
270 report();
271 }
272
Jin Qian5b962c62017-01-30 14:48:38 -0800273 std::unique_ptr<lock_t> lock(new lock_t(&um_lock));
274
Jin Qian81577752017-02-21 12:09:39 -0800275 std::map<uint64_t, struct uid_records> dump_records;
Jin Qian5b962c62017-01-30 14:48:38 -0800276 uint64_t first_ts = 0;
277
278 if (hours != 0) {
Jin Qiandd41d6b2017-02-10 17:23:16 -0800279 first_ts = time(NULL) - hours * HOUR_TO_SEC;
Jin Qian5b962c62017-01-30 14:48:38 -0800280 }
281
Jin Qianebf031b2017-08-14 16:41:24 -0700282 for (auto it = io_history.lower_bound(first_ts); it != io_history.end(); ++it) {
Jin Qian81577752017-02-21 12:09:39 -0800283 const std::vector<struct uid_record>& recs = it->second.entries;
284 struct uid_records filtered;
Jin Qiane5ea17c2017-02-10 10:50:03 -0800285
286 for (const auto& rec : recs) {
Yang Jin3906c892017-06-22 15:18:21 -0700287 const io_usage& uid_usage = rec.ios.uid_ios;
288 if (uid_usage.bytes[READ][FOREGROUND][CHARGER_ON] +
289 uid_usage.bytes[READ][FOREGROUND][CHARGER_OFF] +
290 uid_usage.bytes[READ][BACKGROUND][CHARGER_ON] +
291 uid_usage.bytes[READ][BACKGROUND][CHARGER_OFF] +
292 uid_usage.bytes[WRITE][FOREGROUND][CHARGER_ON] +
293 uid_usage.bytes[WRITE][FOREGROUND][CHARGER_OFF] +
294 uid_usage.bytes[WRITE][BACKGROUND][CHARGER_ON] +
295 uid_usage.bytes[WRITE][BACKGROUND][CHARGER_OFF] > threshold) {
Jin Qian81577752017-02-21 12:09:39 -0800296 filtered.entries.push_back(rec);
Jin Qiane5ea17c2017-02-10 10:50:03 -0800297 }
298 }
Jin Qian81577752017-02-21 12:09:39 -0800299
300 if (filtered.entries.empty())
301 continue;
302
303 filtered.start_ts = it->second.start_ts;
Jin Qiane5ea17c2017-02-10 10:50:03 -0800304 dump_records.insert(
Jin Qian81577752017-02-21 12:09:39 -0800305 std::pair<uint64_t, struct uid_records>(it->first, filtered));
Jin Qiane5ea17c2017-02-10 10:50:03 -0800306 }
Jin Qian5b962c62017-01-30 14:48:38 -0800307
308 return dump_records;
309}
310
311void uid_monitor::update_curr_io_stats_locked()
312{
313 std::unordered_map<uint32_t, struct uid_info> uid_io_stats =
314 get_uid_io_stats_locked();
315 if (uid_io_stats.empty()) {
316 return;
317 }
318
319 for (const auto& it : uid_io_stats) {
320 const struct uid_info& uid = it.second;
321
322 if (curr_io_stats.find(uid.name) == curr_io_stats.end()) {
323 curr_io_stats[uid.name] = {};
324 }
325
326 struct uid_io_usage& usage = curr_io_stats[uid.name];
Jin Qianbaff6402017-02-16 18:34:31 -0800327 int64_t fg_rd_delta = uid.io[FOREGROUND].read_bytes -
Jin Qian5b962c62017-01-30 14:48:38 -0800328 last_uid_io_stats[uid.uid].io[FOREGROUND].read_bytes;
Jin Qianbaff6402017-02-16 18:34:31 -0800329 int64_t bg_rd_delta = uid.io[BACKGROUND].read_bytes -
Jin Qian5b962c62017-01-30 14:48:38 -0800330 last_uid_io_stats[uid.uid].io[BACKGROUND].read_bytes;
Jin Qianbaff6402017-02-16 18:34:31 -0800331 int64_t fg_wr_delta = uid.io[FOREGROUND].write_bytes -
Jin Qian5b962c62017-01-30 14:48:38 -0800332 last_uid_io_stats[uid.uid].io[FOREGROUND].write_bytes;
Jin Qianbaff6402017-02-16 18:34:31 -0800333 int64_t bg_wr_delta = uid.io[BACKGROUND].write_bytes -
334 last_uid_io_stats[uid.uid].io[BACKGROUND].write_bytes;
335
Yang Jin3906c892017-06-22 15:18:21 -0700336 usage.uid_ios.bytes[READ][FOREGROUND][charger_stat] +=
337 (fg_rd_delta < 0) ? 0 : fg_rd_delta;
338 usage.uid_ios.bytes[READ][BACKGROUND][charger_stat] +=
339 (bg_rd_delta < 0) ? 0 : bg_rd_delta;
340 usage.uid_ios.bytes[WRITE][FOREGROUND][charger_stat] +=
341 (fg_wr_delta < 0) ? 0 : fg_wr_delta;
342 usage.uid_ios.bytes[WRITE][BACKGROUND][charger_stat] +=
343 (bg_wr_delta < 0) ? 0 : bg_wr_delta;
344
345 for (const auto& task_it : uid.tasks) {
346 const struct task_info& task = task_it.second;
347 const pid_t pid = task_it.first;
348 const std::string& comm = task_it.second.comm;
349 int64_t task_fg_rd_delta = task.io[FOREGROUND].read_bytes -
350 last_uid_io_stats[uid.uid].tasks[pid].io[FOREGROUND].read_bytes;
351 int64_t task_bg_rd_delta = task.io[BACKGROUND].read_bytes -
352 last_uid_io_stats[uid.uid].tasks[pid].io[BACKGROUND].read_bytes;
353 int64_t task_fg_wr_delta = task.io[FOREGROUND].write_bytes -
354 last_uid_io_stats[uid.uid].tasks[pid].io[FOREGROUND].write_bytes;
355 int64_t task_bg_wr_delta = task.io[BACKGROUND].write_bytes -
356 last_uid_io_stats[uid.uid].tasks[pid].io[BACKGROUND].write_bytes;
357
358 struct io_usage& task_usage = usage.task_ios[comm];
359 task_usage.bytes[READ][FOREGROUND][charger_stat] +=
360 (task_fg_rd_delta < 0) ? 0 : task_fg_rd_delta;
361 task_usage.bytes[READ][BACKGROUND][charger_stat] +=
362 (task_bg_rd_delta < 0) ? 0 : task_bg_rd_delta;
363 task_usage.bytes[WRITE][FOREGROUND][charger_stat] +=
364 (task_fg_wr_delta < 0) ? 0 : task_fg_wr_delta;
365 task_usage.bytes[WRITE][BACKGROUND][charger_stat] +=
366 (task_bg_wr_delta < 0) ? 0 : task_bg_wr_delta;
367 }
Jin Qian5b962c62017-01-30 14:48:38 -0800368 }
369
370 last_uid_io_stats = uid_io_stats;
Jin Qiana2e5bd12017-01-24 16:23:13 -0800371}
372
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800373void uid_monitor::report()
374{
Jin Qian5b962c62017-01-30 14:48:38 -0800375 std::unique_ptr<lock_t> lock(new lock_t(&um_lock));
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800376
Jin Qian5b962c62017-01-30 14:48:38 -0800377 update_curr_io_stats_locked();
378 add_records_locked(time(NULL));
Jin Qianebf031b2017-08-14 16:41:24 -0700379
380 flush_io_history_to_proto();
381}
382
Jin Qian65dea712017-08-29 16:48:20 -0700383namespace {
384
385void set_io_usage_proto(IOUsage* usage_proto, const struct io_usage& usage)
Jin Qianebf031b2017-08-14 16:41:24 -0700386{
387 usage_proto->set_rd_fg_chg_on(usage.bytes[READ][FOREGROUND][CHARGER_ON]);
388 usage_proto->set_rd_fg_chg_off(usage.bytes[READ][FOREGROUND][CHARGER_OFF]);
389 usage_proto->set_rd_bg_chg_on(usage.bytes[READ][BACKGROUND][CHARGER_ON]);
390 usage_proto->set_rd_bg_chg_off(usage.bytes[READ][BACKGROUND][CHARGER_OFF]);
391 usage_proto->set_wr_fg_chg_on(usage.bytes[WRITE][FOREGROUND][CHARGER_ON]);
392 usage_proto->set_wr_fg_chg_off(usage.bytes[WRITE][FOREGROUND][CHARGER_OFF]);
393 usage_proto->set_wr_bg_chg_on(usage.bytes[WRITE][BACKGROUND][CHARGER_ON]);
394 usage_proto->set_wr_bg_chg_off(usage.bytes[WRITE][BACKGROUND][CHARGER_OFF]);
395}
396
Jin Qian65dea712017-08-29 16:48:20 -0700397void get_io_usage_proto(struct io_usage* usage, const IOUsage& io_proto)
Jin Qianebf031b2017-08-14 16:41:24 -0700398{
399 usage->bytes[READ][FOREGROUND][CHARGER_ON] = io_proto.rd_fg_chg_on();
400 usage->bytes[READ][FOREGROUND][CHARGER_OFF] = io_proto.rd_fg_chg_off();
401 usage->bytes[READ][BACKGROUND][CHARGER_ON] = io_proto.rd_bg_chg_on();
402 usage->bytes[READ][BACKGROUND][CHARGER_OFF] = io_proto.rd_bg_chg_off();
403 usage->bytes[WRITE][FOREGROUND][CHARGER_ON] = io_proto.wr_fg_chg_on();
404 usage->bytes[WRITE][FOREGROUND][CHARGER_OFF] = io_proto.wr_fg_chg_off();
405 usage->bytes[WRITE][BACKGROUND][CHARGER_ON] = io_proto.wr_bg_chg_on();
406 usage->bytes[WRITE][BACKGROUND][CHARGER_OFF] = io_proto.wr_bg_chg_off();
407}
408
Jin Qian65dea712017-08-29 16:48:20 -0700409} // namespace
410
Jin Qianebf031b2017-08-14 16:41:24 -0700411void uid_monitor::flush_io_history_to_proto()
412{
413 UidIOHistoryProto out_proto;
414
415 for (const auto& item : io_history) {
416 const uint64_t& end_ts = item.first;
417 const struct uid_records& recs = item.second;
418
419 UidIOItem* item_proto = out_proto.add_items();
420 item_proto->set_end_ts(end_ts);
421
422 UidIORecords* recs_proto = item_proto->mutable_records();
423 recs_proto->set_start_ts(recs.start_ts);
424
425 for (const auto& entry : recs.entries) {
426 UidRecord* rec_proto = recs_proto->add_entries();
427 rec_proto->set_uid_name(entry.name);
428
429 IOUsage* uid_io_proto = rec_proto->mutable_uid_io();
430 const struct io_usage& uio_ios = entry.ios.uid_ios;
431 set_io_usage_proto(uid_io_proto, uio_ios);
432
433 for (const auto& task_io : entry.ios.task_ios) {
434 const std::string& task_name = task_io.first;
435 const struct io_usage& task_ios = task_io.second;
436
437 TaskIOUsage* task_io_proto = rec_proto->add_task_io();
438 task_io_proto->set_task_name(task_name);
439 set_io_usage_proto(task_io_proto->mutable_ios(), task_ios);
440 }
441 }
442 }
443
444 out_proto.set_crc(crc_init);
445 std::string out_proto_str = out_proto.SerializeAsString();
446 out_proto.set_crc(crc32(crc_init,
447 reinterpret_cast<const Bytef*>(out_proto_str.c_str()),
448 out_proto_str.size()));
449
450 std::string tmp_file = io_history_proto_file + "_tmp";
451 std::ofstream out(tmp_file,
452 std::ofstream::out | std::ofstream::binary | std::ofstream::trunc);
453 out << out_proto.SerializeAsString();
454 out.close();
455
456 /* Atomically replace existing proto file to reduce chance of data loss. */
457 rename(tmp_file.c_str(), io_history_proto_file.c_str());
458}
459
460void uid_monitor::load_io_history_from_proto()
461{
462 std::ifstream in(io_history_proto_file,
463 std::ofstream::in | std::ofstream::binary);
464
465 if (!in.good()) {
466 PLOG_TO(SYSTEM, INFO) << "Open " << io_history_proto_file << " failed";
467 return;
468 }
469
470 stringstream ss;
471 ss << in.rdbuf();
472 UidIOHistoryProto in_proto;
473 in_proto.ParseFromString(ss.str());
474
475 uint32_t crc = in_proto.crc();
476 in_proto.set_crc(crc_init);
477 std::string io_proto_str = in_proto.SerializeAsString();
478 uint32_t computed_crc = crc32(crc_init,
479 reinterpret_cast<const Bytef*>(io_proto_str.c_str()),
480 io_proto_str.size());
481
482 if (crc != computed_crc) {
483 LOG_TO(SYSTEM, WARNING) << "CRC mismatch in " << io_history_proto_file;
484 return;
485 }
486
487 for (const auto& item_proto : in_proto.items()) {
488 const UidIORecords& records_proto = item_proto.records();
489 struct uid_records* recs = &io_history[item_proto.end_ts()];
490
491 recs->start_ts = records_proto.start_ts();
492 for (const auto& rec_proto : records_proto.entries()) {
493 struct uid_record record;
494 record.name = rec_proto.uid_name();
495 get_io_usage_proto(&record.ios.uid_ios, rec_proto.uid_io());
496
497 for (const auto& task_io_proto : rec_proto.task_io()) {
498 get_io_usage_proto(
499 &record.ios.task_ios[task_io_proto.task_name()],
500 task_io_proto.ios());
501 }
502 recs->entries.push_back(record);
503 }
504 }
Jin Qian5b962c62017-01-30 14:48:38 -0800505}
506
507void uid_monitor::set_charger_state(charger_stat_t stat)
508{
509 std::unique_ptr<lock_t> lock(new lock_t(&um_lock));
510
511 if (charger_stat == stat) {
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800512 return;
513 }
514
Jin Qian5b962c62017-01-30 14:48:38 -0800515 update_curr_io_stats_locked();
516 charger_stat = stat;
517}
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800518
Jin Qian5b962c62017-01-30 14:48:38 -0800519void uid_monitor::init(charger_stat_t stat)
520{
521 charger_stat = stat;
Jin Qianebf031b2017-08-14 16:41:24 -0700522
523 load_io_history_from_proto();
524
Jin Qian81577752017-02-21 12:09:39 -0800525 start_ts = time(NULL);
Jin Qian5b962c62017-01-30 14:48:38 -0800526 last_uid_io_stats = get_uid_io_stats();
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800527}
528
529uid_monitor::uid_monitor()
Jin Qian65dea712017-08-29 16:48:20 -0700530 : enable(!access(UID_IO_STATS_PATH, R_OK))
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800531{
Jin Qian5b962c62017-01-30 14:48:38 -0800532 sem_init(&um_lock, 0, 1);
Jin Qiana2e5bd12017-01-24 16:23:13 -0800533}
534
535uid_monitor::~uid_monitor()
536{
Jin Qian5b962c62017-01-30 14:48:38 -0800537 sem_destroy(&um_lock);
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800538}