blob: 4105dae8f0db1570242823d20be2b8c8f230de27 [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
36static const uint64_t io_alert_threshold = 1024 * 1024 * 1024; // 1GB
37
38using namespace android;
39using namespace android::base;
40
41static bool packagelist_parse_cb(pkg_info* info, void* userdata)
42{
43 std::unordered_map<uint32_t, struct uid_info>* uids =
44 reinterpret_cast<std::unordered_map<uint32_t, struct uid_info>*>(userdata);
45
46 if (uids->find(info->uid) != uids->end()) {
47 (*uids)[info->uid].name = info->name;
48 }
49
50 packagelist_free(info);
51 return true;
52}
53
54void uid_monitor::set_last_uids(std::unordered_map<uint32_t, struct uid_info>&& uids,
55 uint64_t ts)
56{
57 last_uids = uids;
58 last_report_ts = ts;
59}
60
61std::unordered_map<uint32_t, struct uid_info> uid_monitor::get_uids()
62{
63 std::unordered_map<uint32_t, struct uid_info> uids;
64 std::string buffer;
65 if (!android::base::ReadFileToString(UID_IO_STATS_PATH, &buffer)) {
66 PLOG_TO(SYSTEM, ERROR) << UID_IO_STATS_PATH << ": ReadFileToString failed";
67 return uids;
68 }
69
70 std::stringstream ss(buffer);
71 struct uid_info u;
72 bool refresh_uid = false;
73
74 while (ss >> u.uid) {
75 ss >> u.io[UID_FOREGROUND].rchar >> u.io[UID_FOREGROUND].wchar
76 >> u.io[UID_FOREGROUND].read_bytes >> u.io[UID_FOREGROUND].write_bytes
77 >> u.io[UID_BACKGROUND].rchar >> u.io[UID_BACKGROUND].wchar
78 >> u.io[UID_BACKGROUND].read_bytes >> u.io[UID_BACKGROUND].write_bytes;
79
80 if (!ss.good()) {
81 ss.clear(std::ios_base::badbit);
82 break;
83 }
84
85 if (last_uids.find(u.uid) == last_uids.end()) {
86 refresh_uid = true;
87 u.name = std::to_string(u.uid);
88 } else {
89 u.name = last_uids[u.uid].name;
90 }
91 uids[u.uid] = u;
92 }
93
94 if (!ss.eof() || ss.bad()) {
95 uids.clear();
96 LOG_TO(SYSTEM, ERROR) << "read UID IO stats failed";
97 }
98
99 if (refresh_uid) {
100 packagelist_parse(packagelist_parse_cb, &uids);
101 }
102
103 return uids;
104}
105
106void uid_monitor::report()
107{
108 struct timespec ts;
109
110 // Use monotonic to exclude suspend time so that we measure IO bytes/sec
111 // when system is running.
112 if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) {
113 PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed";
114 return;
115 }
116
117 uint64_t curr_ts = ts.tv_sec * NS_PER_SEC + ts.tv_nsec;
118 uint64_t ts_delta = curr_ts - last_report_ts;
119 uint64_t adjusted_threshold = io_alert_threshold * ((double)ts_delta / interval / NS_PER_SEC);
120
121 std::unordered_map<uint32_t, struct uid_info> uids = get_uids();
122 if (uids.empty()) {
123 return;
124 }
125
126 for (const auto& it : uids) {
127 const struct uid_info& uid = it.second;
128 uint64_t bg_read_delta = uid.io[UID_BACKGROUND].read_bytes -
129 last_uids[uid.uid].io[UID_BACKGROUND].read_bytes;
130 uint64_t bg_write_delta = uid.io[UID_BACKGROUND].write_bytes -
131 last_uids[uid.uid].io[UID_BACKGROUND].write_bytes;
132
133 if (bg_read_delta + bg_write_delta >= adjusted_threshold) {
134 android_log_event_list(EVENTLOGTAG_UID_IO_ALERT)
135 << uid.name << bg_read_delta << bg_write_delta
136 << uint64_t(ts_delta / NS_PER_SEC) << LOG_ID_EVENTS;
137 }
138 }
139
140 set_last_uids(std::move(uids), curr_ts);
141}
142
143uid_monitor::uid_monitor()
144{
145 struct timespec ts;
146
147 if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) {
148 PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed";
149 return;
150 }
151 last_report_ts = ts.tv_sec * NS_PER_SEC + ts.tv_nsec;
152}