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