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 <stdint.h>
20 #include <time.h>
21
22 #include <string>
23 #include <unordered_map>
24
25 #include <android-base/file.h>
26 #include <android-base/logging.h>
27 #include <android-base/macros.h>
28 #include <android-base/parseint.h>
29 #include <android-base/strings.h>
30 #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
37 using namespace android;
38 using namespace android::base;
39
packagelist_parse_cb(pkg_info * info,void * userdata)40 static 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
get_uid_io_stats()53 std::unordered_map<uint32_t, struct uid_info> uid_monitor::get_uid_io_stats()
54 {
55 std::unique_ptr<lock_t> lock(new lock_t(&um_lock));
56 return get_uid_io_stats_locked();
57 };
58
get_uid_io_stats_locked()59 std::unordered_map<uint32_t, struct uid_info> uid_monitor::get_uid_io_stats_locked()
60 {
61 std::unordered_map<uint32_t, struct uid_info> uid_io_stats;
62 std::string buffer;
63 if (!ReadFileToString(UID_IO_STATS_PATH, &buffer)) {
64 PLOG_TO(SYSTEM, ERROR) << UID_IO_STATS_PATH << ": ReadFileToString failed";
65 return uid_io_stats;
66 }
67
68 std::vector<std::string> io_stats = Split(buffer, "\n");
69 struct uid_info u;
70 bool refresh_uid = false;
71
72 for (uint32_t i = 0; i < io_stats.size(); i++) {
73 if (io_stats[i].empty()) {
74 continue;
75 }
76 std::vector<std::string> fields = Split(io_stats[i], " ");
77 if (fields.size() < 11 ||
78 !ParseUint(fields[0], &u.uid) ||
79 !ParseUint(fields[1], &u.io[FOREGROUND].rchar) ||
80 !ParseUint(fields[2], &u.io[FOREGROUND].wchar) ||
81 !ParseUint(fields[3], &u.io[FOREGROUND].read_bytes) ||
82 !ParseUint(fields[4], &u.io[FOREGROUND].write_bytes) ||
83 !ParseUint(fields[5], &u.io[BACKGROUND].rchar) ||
84 !ParseUint(fields[6], &u.io[BACKGROUND].wchar) ||
85 !ParseUint(fields[7], &u.io[BACKGROUND].read_bytes) ||
86 !ParseUint(fields[8], &u.io[BACKGROUND].write_bytes) ||
87 !ParseUint(fields[9], &u.io[FOREGROUND].fsync) ||
88 !ParseUint(fields[10], &u.io[BACKGROUND].fsync)) {
89 LOG_TO(SYSTEM, WARNING) << "Invalid I/O stats: \""
90 << io_stats[i] << "\"";
91 continue;
92 }
93
94 if (last_uid_io_stats.find(u.uid) == last_uid_io_stats.end()) {
95 refresh_uid = true;
96 u.name = std::to_string(u.uid);
97 } else {
98 u.name = last_uid_io_stats[u.uid].name;
99 }
100 uid_io_stats[u.uid] = u;
101 }
102
103 if (refresh_uid) {
104 packagelist_parse(packagelist_parse_cb, &uid_io_stats);
105 }
106
107 return uid_io_stats;
108 }
109
110 static const int MAX_UID_RECORDS_SIZE = 1000 * 48; // 1000 uids in 48 hours
111
records_size(const std::map<uint64_t,struct uid_records> & curr_records)112 static inline int records_size(
113 const std::map<uint64_t, struct uid_records>& curr_records)
114 {
115 int count = 0;
116 for (auto const& it : curr_records) {
117 count += it.second.entries.size();
118 }
119 return count;
120 }
121
122 static struct uid_io_usage zero_io_usage;
123
add_records_locked(uint64_t curr_ts)124 void uid_monitor::add_records_locked(uint64_t curr_ts)
125 {
126 // remove records more than 5 days old
127 if (curr_ts > 5 * DAY_TO_SEC) {
128 auto it = records.lower_bound(curr_ts - 5 * DAY_TO_SEC);
129 records.erase(records.begin(), it);
130 }
131
132 struct uid_records new_records;
133 for (const auto& p : curr_io_stats) {
134 struct uid_record record = {};
135 record.name = p.first;
136 record.ios = p.second;
137 if (memcmp(&record.ios, &zero_io_usage, sizeof(struct uid_io_usage))) {
138 new_records.entries.push_back(record);
139 }
140 }
141
142 curr_io_stats.clear();
143 new_records.start_ts = start_ts;
144 start_ts = curr_ts;
145
146 if (new_records.entries.empty())
147 return;
148
149 // make some room for new records
150 int overflow = records_size(records) +
151 new_records.entries.size() - MAX_UID_RECORDS_SIZE;
152 while (overflow > 0 && records.size() > 0) {
153 auto del_it = records.begin();
154 overflow -= del_it->second.entries.size();
155 records.erase(records.begin());
156 }
157
158 records[curr_ts] = new_records;
159 }
160
dump(double hours,uint64_t threshold,bool force_report)161 std::map<uint64_t, struct uid_records> uid_monitor::dump(
162 double hours, uint64_t threshold, bool force_report)
163 {
164 if (force_report) {
165 report();
166 }
167
168 std::unique_ptr<lock_t> lock(new lock_t(&um_lock));
169
170 std::map<uint64_t, struct uid_records> dump_records;
171 uint64_t first_ts = 0;
172
173 if (hours != 0) {
174 first_ts = time(NULL) - hours * HOUR_TO_SEC;
175 }
176
177 for (auto it = records.lower_bound(first_ts); it != records.end(); ++it) {
178 const std::vector<struct uid_record>& recs = it->second.entries;
179 struct uid_records filtered;
180
181 for (const auto& rec : recs) {
182 if (rec.ios.bytes[READ][FOREGROUND][CHARGER_ON] +
183 rec.ios.bytes[READ][FOREGROUND][CHARGER_OFF] +
184 rec.ios.bytes[READ][BACKGROUND][CHARGER_ON] +
185 rec.ios.bytes[READ][BACKGROUND][CHARGER_OFF] +
186 rec.ios.bytes[WRITE][FOREGROUND][CHARGER_ON] +
187 rec.ios.bytes[WRITE][FOREGROUND][CHARGER_OFF] +
188 rec.ios.bytes[WRITE][BACKGROUND][CHARGER_ON] +
189 rec.ios.bytes[WRITE][BACKGROUND][CHARGER_OFF] > threshold) {
190 filtered.entries.push_back(rec);
191 }
192 }
193
194 if (filtered.entries.empty())
195 continue;
196
197 filtered.start_ts = it->second.start_ts;
198 dump_records.insert(
199 std::pair<uint64_t, struct uid_records>(it->first, filtered));
200 }
201
202 return dump_records;
203 }
204
update_curr_io_stats_locked()205 void uid_monitor::update_curr_io_stats_locked()
206 {
207 std::unordered_map<uint32_t, struct uid_info> uid_io_stats =
208 get_uid_io_stats_locked();
209 if (uid_io_stats.empty()) {
210 return;
211 }
212
213 for (const auto& it : uid_io_stats) {
214 const struct uid_info& uid = it.second;
215
216 if (curr_io_stats.find(uid.name) == curr_io_stats.end()) {
217 curr_io_stats[uid.name] = {};
218 }
219
220 struct uid_io_usage& usage = curr_io_stats[uid.name];
221 int64_t fg_rd_delta = uid.io[FOREGROUND].read_bytes -
222 last_uid_io_stats[uid.uid].io[FOREGROUND].read_bytes;
223 int64_t bg_rd_delta = uid.io[BACKGROUND].read_bytes -
224 last_uid_io_stats[uid.uid].io[BACKGROUND].read_bytes;
225 int64_t fg_wr_delta = uid.io[FOREGROUND].write_bytes -
226 last_uid_io_stats[uid.uid].io[FOREGROUND].write_bytes;
227 int64_t bg_wr_delta = uid.io[BACKGROUND].write_bytes -
228 last_uid_io_stats[uid.uid].io[BACKGROUND].write_bytes;
229
230 usage.bytes[READ][FOREGROUND][charger_stat] +=
231 (fg_rd_delta < 0) ? uid.io[FOREGROUND].read_bytes : fg_rd_delta;
232 usage.bytes[READ][BACKGROUND][charger_stat] +=
233 (bg_rd_delta < 0) ? uid.io[BACKGROUND].read_bytes : bg_rd_delta;
234 usage.bytes[WRITE][FOREGROUND][charger_stat] +=
235 (fg_wr_delta < 0) ? uid.io[FOREGROUND].write_bytes : fg_wr_delta;
236 usage.bytes[WRITE][BACKGROUND][charger_stat] +=
237 (bg_wr_delta < 0) ? uid.io[BACKGROUND].write_bytes : bg_wr_delta;
238 }
239
240 last_uid_io_stats = uid_io_stats;
241 }
242
report()243 void uid_monitor::report()
244 {
245 std::unique_ptr<lock_t> lock(new lock_t(&um_lock));
246
247 update_curr_io_stats_locked();
248 add_records_locked(time(NULL));
249 }
250
set_charger_state(charger_stat_t stat)251 void uid_monitor::set_charger_state(charger_stat_t stat)
252 {
253 std::unique_ptr<lock_t> lock(new lock_t(&um_lock));
254
255 if (charger_stat == stat) {
256 return;
257 }
258
259 update_curr_io_stats_locked();
260 charger_stat = stat;
261 }
262
init(charger_stat_t stat)263 void uid_monitor::init(charger_stat_t stat)
264 {
265 charger_stat = stat;
266 start_ts = time(NULL);
267 last_uid_io_stats = get_uid_io_stats();
268 }
269
uid_monitor()270 uid_monitor::uid_monitor()
271 {
272 sem_init(&um_lock, 0, 1);
273 }
274
~uid_monitor()275 uid_monitor::~uid_monitor()
276 {
277 sem_destroy(&um_lock);
278 }
279