blob: 78e0a832e0685a261fdd28ab064d913578be12fa [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>
23#include <sstream>
24#include <unordered_map>
25
26#include <android-base/file.h>
27#include <android-base/logging.h>
28#include <android-base/macros.h>
29#include <android-base/stringprintf.h>
30#include <log/log_event_list.h>
31#include <packagelistparser/packagelistparser.h>
32
33#include "storaged.h"
34#include "storaged_uid_monitor.h"
35
Jin Qianbcd6e3b2016-12-28 15:43:51 -080036using namespace android;
37using namespace android::base;
38
39static bool packagelist_parse_cb(pkg_info* info, void* userdata)
40{
41 std::unordered_map<uint32_t, struct uid_info>* uids =
42 reinterpret_cast<std::unordered_map<uint32_t, struct uid_info>*>(userdata);
43
44 if (uids->find(info->uid) != uids->end()) {
45 (*uids)[info->uid].name = info->name;
46 }
47
48 packagelist_free(info);
49 return true;
50}
51
Jin Qian5b962c62017-01-30 14:48:38 -080052std::unordered_map<uint32_t, struct uid_info> uid_monitor::get_uid_io_stats()
Jin Qianbcd6e3b2016-12-28 15:43:51 -080053{
Jin Qian5b962c62017-01-30 14:48:38 -080054 std::unique_ptr<lock_t> lock(new lock_t(&um_lock));
55 return get_uid_io_stats_locked();
56};
Jin Qianbcd6e3b2016-12-28 15:43:51 -080057
Jin Qian5b962c62017-01-30 14:48:38 -080058std::unordered_map<uint32_t, struct uid_info> uid_monitor::get_uid_io_stats_locked()
Jin Qianbcd6e3b2016-12-28 15:43:51 -080059{
Jin Qian5b962c62017-01-30 14:48:38 -080060 std::unordered_map<uint32_t, struct uid_info> uid_io_stats;
Jin Qianbcd6e3b2016-12-28 15:43:51 -080061 std::string buffer;
62 if (!android::base::ReadFileToString(UID_IO_STATS_PATH, &buffer)) {
63 PLOG_TO(SYSTEM, ERROR) << UID_IO_STATS_PATH << ": ReadFileToString failed";
Jin Qian5b962c62017-01-30 14:48:38 -080064 return uid_io_stats;
Jin Qianbcd6e3b2016-12-28 15:43:51 -080065 }
66
67 std::stringstream ss(buffer);
68 struct uid_info u;
69 bool refresh_uid = false;
70
71 while (ss >> u.uid) {
Jin Qian5b962c62017-01-30 14:48:38 -080072 ss >> u.io[FOREGROUND].rchar >> u.io[FOREGROUND].wchar
73 >> u.io[FOREGROUND].read_bytes >> u.io[FOREGROUND].write_bytes
74 >> u.io[BACKGROUND].rchar >> u.io[BACKGROUND].wchar
75 >> u.io[BACKGROUND].read_bytes >> u.io[BACKGROUND].write_bytes;
Jin Qianbcd6e3b2016-12-28 15:43:51 -080076
77 if (!ss.good()) {
78 ss.clear(std::ios_base::badbit);
79 break;
80 }
81
Jin Qian5b962c62017-01-30 14:48:38 -080082 if (last_uid_io_stats.find(u.uid) == last_uid_io_stats.end()) {
Jin Qianbcd6e3b2016-12-28 15:43:51 -080083 refresh_uid = true;
84 u.name = std::to_string(u.uid);
85 } else {
Jin Qian5b962c62017-01-30 14:48:38 -080086 u.name = last_uid_io_stats[u.uid].name;
Jin Qianbcd6e3b2016-12-28 15:43:51 -080087 }
Jin Qian5b962c62017-01-30 14:48:38 -080088 uid_io_stats[u.uid] = u;
Jin Qianbcd6e3b2016-12-28 15:43:51 -080089 }
90
91 if (!ss.eof() || ss.bad()) {
Jin Qian5b962c62017-01-30 14:48:38 -080092 uid_io_stats.clear();
Jin Qianbcd6e3b2016-12-28 15:43:51 -080093 LOG_TO(SYSTEM, ERROR) << "read UID IO stats failed";
94 }
95
96 if (refresh_uid) {
Jin Qian5b962c62017-01-30 14:48:38 -080097 packagelist_parse(packagelist_parse_cb, &uid_io_stats);
Jin Qianbcd6e3b2016-12-28 15:43:51 -080098 }
99
Jin Qian5b962c62017-01-30 14:48:38 -0800100 return uid_io_stats;
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800101}
102
Jin Qian5b962c62017-01-30 14:48:38 -0800103static const int MAX_UID_RECORDS_SIZE = 1000 * 48; // 1000 uids in 48 hours
Jin Qiana2e5bd12017-01-24 16:23:13 -0800104
Jin Qian5b962c62017-01-30 14:48:38 -0800105static inline int records_size(
Jin Qian81577752017-02-21 12:09:39 -0800106 const std::map<uint64_t, struct uid_records>& curr_records)
Jin Qiana2e5bd12017-01-24 16:23:13 -0800107{
Jin Qian5b962c62017-01-30 14:48:38 -0800108 int count = 0;
Jin Qian81577752017-02-21 12:09:39 -0800109 for (auto const& it : curr_records) {
110 count += it.second.entries.size();
Jin Qian5b962c62017-01-30 14:48:38 -0800111 }
112 return count;
Jin Qiana2e5bd12017-01-24 16:23:13 -0800113}
114
Jin Qian5b962c62017-01-30 14:48:38 -0800115static struct uid_io_usage zero_io_usage;
116
117void uid_monitor::add_records_locked(uint64_t curr_ts)
Jin Qiana2e5bd12017-01-24 16:23:13 -0800118{
Jin Qian5b962c62017-01-30 14:48:38 -0800119 // remove records more than 5 days old
120 if (curr_ts > 5 * DAY_TO_SEC) {
121 auto it = records.lower_bound(curr_ts - 5 * DAY_TO_SEC);
122 records.erase(records.begin(), it);
Jin Qian9cdfdd32017-01-31 17:33:20 -0800123 }
124
Jin Qian81577752017-02-21 12:09:39 -0800125 struct uid_records new_records;
Jin Qian5b962c62017-01-30 14:48:38 -0800126 for (const auto& p : curr_io_stats) {
127 struct uid_record record = {};
128 record.name = p.first;
129 record.ios = p.second;
130 if (memcmp(&record.ios, &zero_io_usage, sizeof(struct uid_io_usage))) {
Jin Qian81577752017-02-21 12:09:39 -0800131 new_records.entries.push_back(record);
Jin Qian5b962c62017-01-30 14:48:38 -0800132 }
Jin Qian9cdfdd32017-01-31 17:33:20 -0800133 }
Jin Qian9cdfdd32017-01-31 17:33:20 -0800134
Jin Qian5b962c62017-01-30 14:48:38 -0800135 curr_io_stats.clear();
Jin Qian81577752017-02-21 12:09:39 -0800136 new_records.start_ts = start_ts;
137 start_ts = curr_ts;
Jin Qian9cdfdd32017-01-31 17:33:20 -0800138
Jin Qian81577752017-02-21 12:09:39 -0800139 if (new_records.entries.empty())
Jin Qian5b962c62017-01-30 14:48:38 -0800140 return;
141
142 // make some room for new records
143 int overflow = records_size(records) +
Jin Qian81577752017-02-21 12:09:39 -0800144 new_records.entries.size() - MAX_UID_RECORDS_SIZE;
Jin Qian5b962c62017-01-30 14:48:38 -0800145 while (overflow > 0 && records.size() > 0) {
Jin Qian81577752017-02-21 12:09:39 -0800146 auto del_it = records.begin();
147 overflow -= del_it->second.entries.size();
Jin Qian5b962c62017-01-30 14:48:38 -0800148 records.erase(records.begin());
149 }
150
Jin Qian81577752017-02-21 12:09:39 -0800151 records[curr_ts] = new_records;
Jin Qian5b962c62017-01-30 14:48:38 -0800152}
153
Jin Qian81577752017-02-21 12:09:39 -0800154std::map<uint64_t, struct uid_records> uid_monitor::dump(
Jin Qiandd41d6b2017-02-10 17:23:16 -0800155 double hours, uint64_t threshold, bool force_report)
Jin Qian5b962c62017-01-30 14:48:38 -0800156{
Jin Qian1275b1b2017-02-06 14:02:50 -0800157 if (force_report) {
158 report();
159 }
160
Jin Qian5b962c62017-01-30 14:48:38 -0800161 std::unique_ptr<lock_t> lock(new lock_t(&um_lock));
162
Jin Qian81577752017-02-21 12:09:39 -0800163 std::map<uint64_t, struct uid_records> dump_records;
Jin Qian5b962c62017-01-30 14:48:38 -0800164 uint64_t first_ts = 0;
165
166 if (hours != 0) {
Jin Qiandd41d6b2017-02-10 17:23:16 -0800167 first_ts = time(NULL) - hours * HOUR_TO_SEC;
Jin Qian5b962c62017-01-30 14:48:38 -0800168 }
169
Jin Qiane5ea17c2017-02-10 10:50:03 -0800170 for (auto it = records.lower_bound(first_ts); it != records.end(); ++it) {
Jin Qian81577752017-02-21 12:09:39 -0800171 const std::vector<struct uid_record>& recs = it->second.entries;
172 struct uid_records filtered;
Jin Qiane5ea17c2017-02-10 10:50:03 -0800173
174 for (const auto& rec : recs) {
175 if (rec.ios.bytes[READ][FOREGROUND][CHARGER_ON] +
176 rec.ios.bytes[READ][FOREGROUND][CHARGER_OFF] +
177 rec.ios.bytes[READ][BACKGROUND][CHARGER_ON] +
178 rec.ios.bytes[READ][BACKGROUND][CHARGER_OFF] +
179 rec.ios.bytes[WRITE][FOREGROUND][CHARGER_ON] +
180 rec.ios.bytes[WRITE][FOREGROUND][CHARGER_OFF] +
181 rec.ios.bytes[WRITE][BACKGROUND][CHARGER_ON] +
182 rec.ios.bytes[WRITE][BACKGROUND][CHARGER_OFF] > threshold) {
Jin Qian81577752017-02-21 12:09:39 -0800183 filtered.entries.push_back(rec);
Jin Qiane5ea17c2017-02-10 10:50:03 -0800184 }
185 }
Jin Qian81577752017-02-21 12:09:39 -0800186
187 if (filtered.entries.empty())
188 continue;
189
190 filtered.start_ts = it->second.start_ts;
Jin Qiane5ea17c2017-02-10 10:50:03 -0800191 dump_records.insert(
Jin Qian81577752017-02-21 12:09:39 -0800192 std::pair<uint64_t, struct uid_records>(it->first, filtered));
Jin Qiane5ea17c2017-02-10 10:50:03 -0800193 }
Jin Qian5b962c62017-01-30 14:48:38 -0800194
195 return dump_records;
196}
197
198void uid_monitor::update_curr_io_stats_locked()
199{
200 std::unordered_map<uint32_t, struct uid_info> uid_io_stats =
201 get_uid_io_stats_locked();
202 if (uid_io_stats.empty()) {
203 return;
204 }
205
206 for (const auto& it : uid_io_stats) {
207 const struct uid_info& uid = it.second;
208
209 if (curr_io_stats.find(uid.name) == curr_io_stats.end()) {
210 curr_io_stats[uid.name] = {};
211 }
212
213 struct uid_io_usage& usage = curr_io_stats[uid.name];
Jin Qianbaff6402017-02-16 18:34:31 -0800214 int64_t fg_rd_delta = uid.io[FOREGROUND].read_bytes -
Jin Qian5b962c62017-01-30 14:48:38 -0800215 last_uid_io_stats[uid.uid].io[FOREGROUND].read_bytes;
Jin Qianbaff6402017-02-16 18:34:31 -0800216 int64_t bg_rd_delta = uid.io[BACKGROUND].read_bytes -
Jin Qian5b962c62017-01-30 14:48:38 -0800217 last_uid_io_stats[uid.uid].io[BACKGROUND].read_bytes;
Jin Qianbaff6402017-02-16 18:34:31 -0800218 int64_t fg_wr_delta = uid.io[FOREGROUND].write_bytes -
Jin Qian5b962c62017-01-30 14:48:38 -0800219 last_uid_io_stats[uid.uid].io[FOREGROUND].write_bytes;
Jin Qianbaff6402017-02-16 18:34:31 -0800220 int64_t bg_wr_delta = uid.io[BACKGROUND].write_bytes -
221 last_uid_io_stats[uid.uid].io[BACKGROUND].write_bytes;
222
223 usage.bytes[READ][FOREGROUND][charger_stat] +=
224 (fg_rd_delta < 0) ? uid.io[FOREGROUND].read_bytes : fg_rd_delta;
225 usage.bytes[READ][BACKGROUND][charger_stat] +=
226 (bg_rd_delta < 0) ? uid.io[BACKGROUND].read_bytes : bg_rd_delta;
227 usage.bytes[WRITE][FOREGROUND][charger_stat] +=
228 (fg_wr_delta < 0) ? uid.io[FOREGROUND].write_bytes : fg_wr_delta;
Jin Qian5b962c62017-01-30 14:48:38 -0800229 usage.bytes[WRITE][BACKGROUND][charger_stat] +=
Jin Qianbaff6402017-02-16 18:34:31 -0800230 (bg_wr_delta < 0) ? uid.io[BACKGROUND].write_bytes : bg_wr_delta;
Jin Qian5b962c62017-01-30 14:48:38 -0800231 }
232
233 last_uid_io_stats = uid_io_stats;
Jin Qiana2e5bd12017-01-24 16:23:13 -0800234}
235
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800236void uid_monitor::report()
237{
Jin Qian5b962c62017-01-30 14:48:38 -0800238 std::unique_ptr<lock_t> lock(new lock_t(&um_lock));
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800239
Jin Qian5b962c62017-01-30 14:48:38 -0800240 update_curr_io_stats_locked();
241 add_records_locked(time(NULL));
242}
243
244void uid_monitor::set_charger_state(charger_stat_t stat)
245{
246 std::unique_ptr<lock_t> lock(new lock_t(&um_lock));
247
248 if (charger_stat == stat) {
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800249 return;
250 }
251
Jin Qian5b962c62017-01-30 14:48:38 -0800252 update_curr_io_stats_locked();
253 charger_stat = stat;
254}
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800255
Jin Qian5b962c62017-01-30 14:48:38 -0800256void uid_monitor::init(charger_stat_t stat)
257{
258 charger_stat = stat;
Jin Qian81577752017-02-21 12:09:39 -0800259 start_ts = time(NULL);
Jin Qian5b962c62017-01-30 14:48:38 -0800260 last_uid_io_stats = get_uid_io_stats();
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800261}
262
263uid_monitor::uid_monitor()
264{
Jin Qian5b962c62017-01-30 14:48:38 -0800265 sem_init(&um_lock, 0, 1);
Jin Qiana2e5bd12017-01-24 16:23:13 -0800266}
267
268uid_monitor::~uid_monitor()
269{
Jin Qian5b962c62017-01-30 14:48:38 -0800270 sem_destroy(&um_lock);
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800271}