blob: 2c20dba1df5bd82bf48eb97dbc8418653fc0a887 [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(
106 const std::map<uint64_t, std::vector<struct uid_record>>& records)
Jin Qiana2e5bd12017-01-24 16:23:13 -0800107{
Jin Qian5b962c62017-01-30 14:48:38 -0800108 int count = 0;
109 for (auto const& it : records) {
110 count += it.second.size();
111 }
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 Qian5b962c62017-01-30 14:48:38 -0800125 std::vector<struct uid_record> new_records;
126 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))) {
131 new_records.push_back(record);
132 }
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 Qian9cdfdd32017-01-31 17:33:20 -0800136
Jin Qian5b962c62017-01-30 14:48:38 -0800137 if (new_records.empty())
138 return;
139
140 // make some room for new records
141 int overflow = records_size(records) +
142 new_records.size() - MAX_UID_RECORDS_SIZE;
143 while (overflow > 0 && records.size() > 0) {
144 overflow -= records[0].size();
145 records.erase(records.begin());
146 }
147
148 records[curr_ts].insert(records[curr_ts].end(),
149 new_records.begin(), new_records.end());
150}
151
Jin Qiane5ea17c2017-02-10 10:50:03 -0800152std::map<uint64_t, std::vector<struct uid_record>> uid_monitor::dump(
Jin Qian1275b1b2017-02-06 14:02:50 -0800153 int hours, uint64_t threshold, bool force_report)
Jin Qian5b962c62017-01-30 14:48:38 -0800154{
Jin Qian1275b1b2017-02-06 14:02:50 -0800155 if (force_report) {
156 report();
157 }
158
Jin Qian5b962c62017-01-30 14:48:38 -0800159 std::unique_ptr<lock_t> lock(new lock_t(&um_lock));
160
161 std::map<uint64_t, std::vector<struct uid_record>> dump_records;
162 uint64_t first_ts = 0;
163
164 if (hours != 0) {
165 first_ts = time(NULL) - (uint64_t)hours * HOUR_TO_SEC;
166 }
167
Jin Qiane5ea17c2017-02-10 10:50:03 -0800168 for (auto it = records.lower_bound(first_ts); it != records.end(); ++it) {
169 const std::vector<struct uid_record>& recs = it->second;
170 std::vector<struct uid_record> filtered;
171
172 for (const auto& rec : recs) {
173 if (rec.ios.bytes[READ][FOREGROUND][CHARGER_ON] +
174 rec.ios.bytes[READ][FOREGROUND][CHARGER_OFF] +
175 rec.ios.bytes[READ][BACKGROUND][CHARGER_ON] +
176 rec.ios.bytes[READ][BACKGROUND][CHARGER_OFF] +
177 rec.ios.bytes[WRITE][FOREGROUND][CHARGER_ON] +
178 rec.ios.bytes[WRITE][FOREGROUND][CHARGER_OFF] +
179 rec.ios.bytes[WRITE][BACKGROUND][CHARGER_ON] +
180 rec.ios.bytes[WRITE][BACKGROUND][CHARGER_OFF] > threshold) {
181 filtered.push_back(rec);
182 }
183 }
184 dump_records.insert(
185 std::pair<uint64_t, std::vector<struct uid_record>>(it->first, filtered));
186 }
Jin Qian5b962c62017-01-30 14:48:38 -0800187
188 return dump_records;
189}
190
191void uid_monitor::update_curr_io_stats_locked()
192{
193 std::unordered_map<uint32_t, struct uid_info> uid_io_stats =
194 get_uid_io_stats_locked();
195 if (uid_io_stats.empty()) {
196 return;
197 }
198
199 for (const auto& it : uid_io_stats) {
200 const struct uid_info& uid = it.second;
201
202 if (curr_io_stats.find(uid.name) == curr_io_stats.end()) {
203 curr_io_stats[uid.name] = {};
204 }
205
206 struct uid_io_usage& usage = curr_io_stats[uid.name];
207 usage.bytes[READ][FOREGROUND][charger_stat] +=
208 uid.io[FOREGROUND].read_bytes -
209 last_uid_io_stats[uid.uid].io[FOREGROUND].read_bytes;
210 usage.bytes[READ][BACKGROUND][charger_stat] +=
211 uid.io[BACKGROUND].read_bytes -
212 last_uid_io_stats[uid.uid].io[BACKGROUND].read_bytes;
213 usage.bytes[WRITE][FOREGROUND][charger_stat] +=
214 uid.io[FOREGROUND].write_bytes -
215 last_uid_io_stats[uid.uid].io[FOREGROUND].write_bytes;
216 usage.bytes[WRITE][BACKGROUND][charger_stat] +=
217 uid.io[BACKGROUND].write_bytes -
218 last_uid_io_stats[uid.uid].io[BACKGROUND].write_bytes;;
219 }
220
221 last_uid_io_stats = uid_io_stats;
Jin Qiana2e5bd12017-01-24 16:23:13 -0800222}
223
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800224void uid_monitor::report()
225{
Jin Qian5b962c62017-01-30 14:48:38 -0800226 std::unique_ptr<lock_t> lock(new lock_t(&um_lock));
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800227
Jin Qian5b962c62017-01-30 14:48:38 -0800228 update_curr_io_stats_locked();
229 add_records_locked(time(NULL));
230}
231
232void uid_monitor::set_charger_state(charger_stat_t stat)
233{
234 std::unique_ptr<lock_t> lock(new lock_t(&um_lock));
235
236 if (charger_stat == stat) {
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800237 return;
238 }
239
Jin Qian5b962c62017-01-30 14:48:38 -0800240 update_curr_io_stats_locked();
241 charger_stat = stat;
242}
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800243
Jin Qian5b962c62017-01-30 14:48:38 -0800244void uid_monitor::init(charger_stat_t stat)
245{
246 charger_stat = stat;
247 last_uid_io_stats = get_uid_io_stats();
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800248}
249
250uid_monitor::uid_monitor()
251{
Jin Qian5b962c62017-01-30 14:48:38 -0800252 sem_init(&um_lock, 0, 1);
Jin Qiana2e5bd12017-01-24 16:23:13 -0800253}
254
255uid_monitor::~uid_monitor()
256{
Jin Qian5b962c62017-01-30 14:48:38 -0800257 sem_destroy(&um_lock);
Jin Qianbcd6e3b2016-12-28 15:43:51 -0800258}