blob: 65fa6f9020dde1be0a1c3fcd3e065bb48d1472e8 [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>
20#include <time.h>
21
22#include <string>
Jin Qianbcd6e3b2016-12-28 15:43:51 -080023#include <unordered_map>
24
25#include <android-base/file.h>
26#include <android-base/logging.h>
27#include <android-base/macros.h>
Jin Qian9b1aeae2017-03-14 11:20:02 -070028#include <android-base/parseint.h>
Jin Qiane83a6102017-03-02 16:16:54 -080029#include <android-base/strings.h>
Jin Qianbcd6e3b2016-12-28 15:43:51 -080030#include <android-base/stringprintf.h>
31#include <log/log_event_list.h>
32#include <packagelistparser/packagelistparser.h>
33
34#include "storaged.h"
35#include "storaged_uid_monitor.h"
36
Jin Qianbcd6e3b2016-12-28 15:43:51 -080037using namespace android;
38using namespace android::base;
39
40static bool packagelist_parse_cb(pkg_info* info, void* userdata)
41{
42 std::unordered_map<uint32_t, struct uid_info>* uids =
43 reinterpret_cast<std::unordered_map<uint32_t, struct uid_info>*>(userdata);
44
45 if (uids->find(info->uid) != uids->end()) {
46 (*uids)[info->uid].name = info->name;
47 }
48
49 packagelist_free(info);
50 return true;
51}
52
Jin Qian5b962c62017-01-30 14:48:38 -080053std::unordered_map<uint32_t, struct uid_info> uid_monitor::get_uid_io_stats()
Jin Qianbcd6e3b2016-12-28 15:43:51 -080054{
Jin Qian5b962c62017-01-30 14:48:38 -080055 std::unique_ptr<lock_t> lock(new lock_t(&um_lock));
56 return get_uid_io_stats_locked();
57};
Jin Qianbcd6e3b2016-12-28 15:43:51 -080058
Yang Jin3906c892017-06-22 15:18:21 -070059/* return true on parse success and false on failure */
60bool uid_info::parse_uid_io_stats(std::string&& s)
61{
62 std::vector<std::string> fields = Split(s, " ");
63 if (fields.size() < 11 ||
64 !ParseUint(fields[0], &uid) ||
65 !ParseUint(fields[1], &io[FOREGROUND].rchar) ||
66 !ParseUint(fields[2], &io[FOREGROUND].wchar) ||
67 !ParseUint(fields[3], &io[FOREGROUND].read_bytes) ||
68 !ParseUint(fields[4], &io[FOREGROUND].write_bytes) ||
69 !ParseUint(fields[5], &io[BACKGROUND].rchar) ||
70 !ParseUint(fields[6], &io[BACKGROUND].wchar) ||
71 !ParseUint(fields[7], &io[BACKGROUND].read_bytes) ||
72 !ParseUint(fields[8], &io[BACKGROUND].write_bytes) ||
73 !ParseUint(fields[9], &io[FOREGROUND].fsync) ||
74 !ParseUint(fields[10], &io[BACKGROUND].fsync)) {
75 LOG_TO(SYSTEM, WARNING) << "Invalid I/O stats: \""
76 << s << "\"";
77 return false;
78 }
79 return true;
80}
81
82/* return true on parse success and false on failure */
83bool task_info::parse_task_io_stats(std::string&& s)
84{
85 std::vector<std::string> fields = Split(s, ",");
86 if (fields.size() < 13 ||
87 !ParseInt(fields[2], &pid) ||
88 !ParseUint(fields[3], &io[FOREGROUND].rchar) ||
89 !ParseUint(fields[4], &io[FOREGROUND].wchar) ||
90 !ParseUint(fields[5], &io[FOREGROUND].read_bytes) ||
91 !ParseUint(fields[6], &io[FOREGROUND].write_bytes) ||
92 !ParseUint(fields[7], &io[BACKGROUND].rchar) ||
93 !ParseUint(fields[8], &io[BACKGROUND].wchar) ||
94 !ParseUint(fields[9], &io[BACKGROUND].read_bytes) ||
95 !ParseUint(fields[10], &io[BACKGROUND].write_bytes) ||
96 !ParseUint(fields[11], &io[FOREGROUND].fsync) ||
97 !ParseUint(fields[12], &io[BACKGROUND].fsync)) {
98 LOG_TO(SYSTEM, WARNING) << "Invalid I/O stats: \""
99 << s << "\"";
100 return false;
101 }
102 comm = fields[1];
103 return true;
104}
105
106bool io_usage::is_zero() const
107{
108 for (int i = 0; i < IO_TYPES; i++) {
109 for (int j = 0; j < UID_STATS; j++) {
110 for (int k = 0; k < CHARGER_STATS; k++) {
111 if (bytes[i][j][k])
112 return false;
113 }
114 }
115 }
116 return true;
117}
118
Jin Qian5b962c62017-01-30 14:48:38 -0800119std::unordered_map<uint32_t, struct uid_info> uid_monitor::get_uid_io_stats_locked()
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800120{
Jin Qian5b962c62017-01-30 14:48:38 -0800121 std::unordered_map<uint32_t, struct uid_info> uid_io_stats;
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800122 std::string buffer;
Jin Qian9b1aeae2017-03-14 11:20:02 -0700123 if (!ReadFileToString(UID_IO_STATS_PATH, &buffer)) {
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800124 PLOG_TO(SYSTEM, ERROR) << UID_IO_STATS_PATH << ": ReadFileToString failed";
Jin Qian5b962c62017-01-30 14:48:38 -0800125 return uid_io_stats;
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800126 }
127
Yang Jin3906c892017-06-22 15:18:21 -0700128 std::vector<std::string> io_stats = Split(std::move(buffer), "\n");
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800129 struct uid_info u;
130 bool refresh_uid = false;
131
Jin Qiane83a6102017-03-02 16:16:54 -0800132 for (uint32_t i = 0; i < io_stats.size(); i++) {
133 if (io_stats[i].empty()) {
134 continue;
135 }
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800136
Yang Jin3906c892017-06-22 15:18:21 -0700137 if (io_stats[i].compare(0, 4, "task")) {
138 if (!u.parse_uid_io_stats(std::move(io_stats[i])))
139 continue;
140 if (last_uid_io_stats.find(u.uid) == last_uid_io_stats.end()) {
141 refresh_uid = true;
142 u.name = std::to_string(u.uid);
143 } else
144 u.name = last_uid_io_stats[u.uid].name;
145 uid_io_stats[u.uid] = u;
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800146 } else {
Yang Jin3906c892017-06-22 15:18:21 -0700147 struct task_info t;
148 if (!t.parse_task_io_stats(std::move(io_stats[i])))
149 continue;
150 uid_io_stats[u.uid].tasks[t.pid] = t;
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800151 }
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800152 }
153
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800154 if (refresh_uid) {
Jin Qian5b962c62017-01-30 14:48:38 -0800155 packagelist_parse(packagelist_parse_cb, &uid_io_stats);
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800156 }
157
Jin Qian5b962c62017-01-30 14:48:38 -0800158 return uid_io_stats;
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800159}
160
Jin Qian5b962c62017-01-30 14:48:38 -0800161static const int MAX_UID_RECORDS_SIZE = 1000 * 48; // 1000 uids in 48 hours
Jin Qiana2e5bd12017-01-24 16:23:13 -0800162
Jin Qian5b962c62017-01-30 14:48:38 -0800163static inline int records_size(
Jin Qian81577752017-02-21 12:09:39 -0800164 const std::map<uint64_t, struct uid_records>& curr_records)
Jin Qiana2e5bd12017-01-24 16:23:13 -0800165{
Jin Qian5b962c62017-01-30 14:48:38 -0800166 int count = 0;
Jin Qian81577752017-02-21 12:09:39 -0800167 for (auto const& it : curr_records) {
168 count += it.second.entries.size();
Jin Qian5b962c62017-01-30 14:48:38 -0800169 }
170 return count;
Jin Qiana2e5bd12017-01-24 16:23:13 -0800171}
172
Jin Qian5b962c62017-01-30 14:48:38 -0800173void uid_monitor::add_records_locked(uint64_t curr_ts)
Jin Qiana2e5bd12017-01-24 16:23:13 -0800174{
Jin Qian5b962c62017-01-30 14:48:38 -0800175 // remove records more than 5 days old
176 if (curr_ts > 5 * DAY_TO_SEC) {
177 auto it = records.lower_bound(curr_ts - 5 * DAY_TO_SEC);
178 records.erase(records.begin(), it);
Jin Qian9cdfdd32017-01-31 17:33:20 -0800179 }
180
Jin Qian81577752017-02-21 12:09:39 -0800181 struct uid_records new_records;
Jin Qian5b962c62017-01-30 14:48:38 -0800182 for (const auto& p : curr_io_stats) {
183 struct uid_record record = {};
184 record.name = p.first;
Yang Jin3906c892017-06-22 15:18:21 -0700185 if (!p.second.uid_ios.is_zero()) {
186 record.ios.uid_ios = p.second.uid_ios;
187 for (const auto& p_task : p.second.task_ios) {
188 if (!p_task.second.is_zero())
189 record.ios.task_ios[p_task.first] = p_task.second;
190 }
Jin Qian81577752017-02-21 12:09:39 -0800191 new_records.entries.push_back(record);
Jin Qian5b962c62017-01-30 14:48:38 -0800192 }
Jin Qian9cdfdd32017-01-31 17:33:20 -0800193 }
Jin Qian9cdfdd32017-01-31 17:33:20 -0800194
Jin Qian5b962c62017-01-30 14:48:38 -0800195 curr_io_stats.clear();
Jin Qian81577752017-02-21 12:09:39 -0800196 new_records.start_ts = start_ts;
197 start_ts = curr_ts;
Jin Qian9cdfdd32017-01-31 17:33:20 -0800198
Jin Qian81577752017-02-21 12:09:39 -0800199 if (new_records.entries.empty())
Jin Qian5b962c62017-01-30 14:48:38 -0800200 return;
201
202 // make some room for new records
203 int overflow = records_size(records) +
Jin Qian81577752017-02-21 12:09:39 -0800204 new_records.entries.size() - MAX_UID_RECORDS_SIZE;
Jin Qian5b962c62017-01-30 14:48:38 -0800205 while (overflow > 0 && records.size() > 0) {
Jin Qian81577752017-02-21 12:09:39 -0800206 auto del_it = records.begin();
207 overflow -= del_it->second.entries.size();
Jin Qian5b962c62017-01-30 14:48:38 -0800208 records.erase(records.begin());
209 }
210
Jin Qian81577752017-02-21 12:09:39 -0800211 records[curr_ts] = new_records;
Jin Qian5b962c62017-01-30 14:48:38 -0800212}
213
Jin Qian81577752017-02-21 12:09:39 -0800214std::map<uint64_t, struct uid_records> uid_monitor::dump(
Jin Qiandd41d6b2017-02-10 17:23:16 -0800215 double hours, uint64_t threshold, bool force_report)
Jin Qian5b962c62017-01-30 14:48:38 -0800216{
Jin Qian1275b1b2017-02-06 14:02:50 -0800217 if (force_report) {
218 report();
219 }
220
Jin Qian5b962c62017-01-30 14:48:38 -0800221 std::unique_ptr<lock_t> lock(new lock_t(&um_lock));
222
Jin Qian81577752017-02-21 12:09:39 -0800223 std::map<uint64_t, struct uid_records> dump_records;
Jin Qian5b962c62017-01-30 14:48:38 -0800224 uint64_t first_ts = 0;
225
226 if (hours != 0) {
Jin Qiandd41d6b2017-02-10 17:23:16 -0800227 first_ts = time(NULL) - hours * HOUR_TO_SEC;
Jin Qian5b962c62017-01-30 14:48:38 -0800228 }
229
Jin Qiane5ea17c2017-02-10 10:50:03 -0800230 for (auto it = records.lower_bound(first_ts); it != records.end(); ++it) {
Jin Qian81577752017-02-21 12:09:39 -0800231 const std::vector<struct uid_record>& recs = it->second.entries;
232 struct uid_records filtered;
Jin Qiane5ea17c2017-02-10 10:50:03 -0800233
234 for (const auto& rec : recs) {
Yang Jin3906c892017-06-22 15:18:21 -0700235 const io_usage& uid_usage = rec.ios.uid_ios;
236 if (uid_usage.bytes[READ][FOREGROUND][CHARGER_ON] +
237 uid_usage.bytes[READ][FOREGROUND][CHARGER_OFF] +
238 uid_usage.bytes[READ][BACKGROUND][CHARGER_ON] +
239 uid_usage.bytes[READ][BACKGROUND][CHARGER_OFF] +
240 uid_usage.bytes[WRITE][FOREGROUND][CHARGER_ON] +
241 uid_usage.bytes[WRITE][FOREGROUND][CHARGER_OFF] +
242 uid_usage.bytes[WRITE][BACKGROUND][CHARGER_ON] +
243 uid_usage.bytes[WRITE][BACKGROUND][CHARGER_OFF] > threshold) {
Jin Qian81577752017-02-21 12:09:39 -0800244 filtered.entries.push_back(rec);
Jin Qiane5ea17c2017-02-10 10:50:03 -0800245 }
246 }
Jin Qian81577752017-02-21 12:09:39 -0800247
248 if (filtered.entries.empty())
249 continue;
250
251 filtered.start_ts = it->second.start_ts;
Jin Qiane5ea17c2017-02-10 10:50:03 -0800252 dump_records.insert(
Jin Qian81577752017-02-21 12:09:39 -0800253 std::pair<uint64_t, struct uid_records>(it->first, filtered));
Jin Qiane5ea17c2017-02-10 10:50:03 -0800254 }
Jin Qian5b962c62017-01-30 14:48:38 -0800255
256 return dump_records;
257}
258
259void uid_monitor::update_curr_io_stats_locked()
260{
261 std::unordered_map<uint32_t, struct uid_info> uid_io_stats =
262 get_uid_io_stats_locked();
263 if (uid_io_stats.empty()) {
264 return;
265 }
266
267 for (const auto& it : uid_io_stats) {
268 const struct uid_info& uid = it.second;
269
270 if (curr_io_stats.find(uid.name) == curr_io_stats.end()) {
271 curr_io_stats[uid.name] = {};
272 }
273
274 struct uid_io_usage& usage = curr_io_stats[uid.name];
Jin Qianbaff6402017-02-16 18:34:31 -0800275 int64_t fg_rd_delta = uid.io[FOREGROUND].read_bytes -
Jin Qian5b962c62017-01-30 14:48:38 -0800276 last_uid_io_stats[uid.uid].io[FOREGROUND].read_bytes;
Jin Qianbaff6402017-02-16 18:34:31 -0800277 int64_t bg_rd_delta = uid.io[BACKGROUND].read_bytes -
Jin Qian5b962c62017-01-30 14:48:38 -0800278 last_uid_io_stats[uid.uid].io[BACKGROUND].read_bytes;
Jin Qianbaff6402017-02-16 18:34:31 -0800279 int64_t fg_wr_delta = uid.io[FOREGROUND].write_bytes -
Jin Qian5b962c62017-01-30 14:48:38 -0800280 last_uid_io_stats[uid.uid].io[FOREGROUND].write_bytes;
Jin Qianbaff6402017-02-16 18:34:31 -0800281 int64_t bg_wr_delta = uid.io[BACKGROUND].write_bytes -
282 last_uid_io_stats[uid.uid].io[BACKGROUND].write_bytes;
283
Yang Jin3906c892017-06-22 15:18:21 -0700284 usage.uid_ios.bytes[READ][FOREGROUND][charger_stat] +=
285 (fg_rd_delta < 0) ? 0 : fg_rd_delta;
286 usage.uid_ios.bytes[READ][BACKGROUND][charger_stat] +=
287 (bg_rd_delta < 0) ? 0 : bg_rd_delta;
288 usage.uid_ios.bytes[WRITE][FOREGROUND][charger_stat] +=
289 (fg_wr_delta < 0) ? 0 : fg_wr_delta;
290 usage.uid_ios.bytes[WRITE][BACKGROUND][charger_stat] +=
291 (bg_wr_delta < 0) ? 0 : bg_wr_delta;
292
293 for (const auto& task_it : uid.tasks) {
294 const struct task_info& task = task_it.second;
295 const pid_t pid = task_it.first;
296 const std::string& comm = task_it.second.comm;
297 int64_t task_fg_rd_delta = task.io[FOREGROUND].read_bytes -
298 last_uid_io_stats[uid.uid].tasks[pid].io[FOREGROUND].read_bytes;
299 int64_t task_bg_rd_delta = task.io[BACKGROUND].read_bytes -
300 last_uid_io_stats[uid.uid].tasks[pid].io[BACKGROUND].read_bytes;
301 int64_t task_fg_wr_delta = task.io[FOREGROUND].write_bytes -
302 last_uid_io_stats[uid.uid].tasks[pid].io[FOREGROUND].write_bytes;
303 int64_t task_bg_wr_delta = task.io[BACKGROUND].write_bytes -
304 last_uid_io_stats[uid.uid].tasks[pid].io[BACKGROUND].write_bytes;
305
306 struct io_usage& task_usage = usage.task_ios[comm];
307 task_usage.bytes[READ][FOREGROUND][charger_stat] +=
308 (task_fg_rd_delta < 0) ? 0 : task_fg_rd_delta;
309 task_usage.bytes[READ][BACKGROUND][charger_stat] +=
310 (task_bg_rd_delta < 0) ? 0 : task_bg_rd_delta;
311 task_usage.bytes[WRITE][FOREGROUND][charger_stat] +=
312 (task_fg_wr_delta < 0) ? 0 : task_fg_wr_delta;
313 task_usage.bytes[WRITE][BACKGROUND][charger_stat] +=
314 (task_bg_wr_delta < 0) ? 0 : task_bg_wr_delta;
315 }
Jin Qian5b962c62017-01-30 14:48:38 -0800316 }
317
318 last_uid_io_stats = uid_io_stats;
Jin Qiana2e5bd12017-01-24 16:23:13 -0800319}
320
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800321void uid_monitor::report()
322{
Jin Qian5b962c62017-01-30 14:48:38 -0800323 std::unique_ptr<lock_t> lock(new lock_t(&um_lock));
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800324
Jin Qian5b962c62017-01-30 14:48:38 -0800325 update_curr_io_stats_locked();
326 add_records_locked(time(NULL));
327}
328
329void uid_monitor::set_charger_state(charger_stat_t stat)
330{
331 std::unique_ptr<lock_t> lock(new lock_t(&um_lock));
332
333 if (charger_stat == stat) {
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800334 return;
335 }
336
Jin Qian5b962c62017-01-30 14:48:38 -0800337 update_curr_io_stats_locked();
338 charger_stat = stat;
339}
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800340
Jin Qian5b962c62017-01-30 14:48:38 -0800341void uid_monitor::init(charger_stat_t stat)
342{
343 charger_stat = stat;
Jin Qian81577752017-02-21 12:09:39 -0800344 start_ts = time(NULL);
Jin Qian5b962c62017-01-30 14:48:38 -0800345 last_uid_io_stats = get_uid_io_stats();
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800346}
347
348uid_monitor::uid_monitor()
349{
Jin Qian5b962c62017-01-30 14:48:38 -0800350 sem_init(&um_lock, 0, 1);
Jin Qiana2e5bd12017-01-24 16:23:13 -0800351}
352
353uid_monitor::~uid_monitor()
354{
Jin Qian5b962c62017-01-30 14:48:38 -0800355 sem_destroy(&um_lock);
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800356}