blob: a9d1c172d738cfe056861985c283206490b4329c [file] [log] [blame]
Lakshman Annadorai6094e9a2020-01-31 10:03:33 -08001/**
2 * Copyright (c) 2020, 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 "carwatchdogd"
18#define DEBUG false
19
20#include "IoPerfCollection.h"
21
Lakshman Annadoraiab4d3fd2020-02-06 11:24:56 -080022#include <android-base/stringprintf.h>
23#include <binder/IServiceManager.h>
24#include <cutils/android_filesystem_config.h>
25#include <inttypes.h>
Lakshman Annadorai6094e9a2020-01-31 10:03:33 -080026#include <log/log.h>
Lakshman Annadoraiab4d3fd2020-02-06 11:24:56 -080027#include <pwd.h>
28
29#include <string>
30#include <unordered_map>
31#include <unordered_set>
32#include <vector>
Lakshman Annadorai6094e9a2020-01-31 10:03:33 -080033
34namespace android {
35namespace automotive {
36namespace watchdog {
37
Lakshman Annadoraiab4d3fd2020-02-06 11:24:56 -080038using android::defaultServiceManager;
39using android::IBinder;
40using android::IServiceManager;
41using android::sp;
42using android::String16;
Lakshman Annadorai6094e9a2020-01-31 10:03:33 -080043using android::base::Error;
Lakshman Annadorai6094e9a2020-01-31 10:03:33 -080044using android::base::Result;
Lakshman Annadoraiab4d3fd2020-02-06 11:24:56 -080045using android::base::StringAppendF;
46using android::content::pm::IPackageManagerNative;
47
48namespace {
49
50double percentage(uint64_t numer, uint64_t denom) {
51 return denom == 0 ? 0.0 : (static_cast<double>(numer) / static_cast<double>(denom)) * 100.0;
52}
53
54} // namespace
55
56std::string toString(const UidIoPerfData& data) {
57 std::string buffer;
58 StringAppendF(&buffer, "Top N Reads:\n");
59 StringAppendF(&buffer,
60 "Android User ID, Package Name, Foreground Bytes, Foreground Bytes %%, "
61 "Foreground Fsync, Foreground Fsync %%, Background Bytes, Background Bytes %%, "
62 "Background Fsync, Background Fsync %%\n");
63 for (const auto& stat : data.topNReads) {
64 StringAppendF(&buffer, "%" PRIu32 ", %s", stat.userId, stat.packageName.c_str());
65 for (int i = 0; i < UID_STATES; ++i) {
66 StringAppendF(&buffer, ", %" PRIu64 ", %.2f%%, %" PRIu64 ", %.2f%%", stat.bytes[i],
67 stat.bytesPercent[i], stat.fsync[i], stat.fsyncPercent[i]);
68 }
69 StringAppendF(&buffer, "\n");
70 }
71 StringAppendF(&buffer, "Top N Writes:\n");
72 StringAppendF(&buffer,
73 "Android User ID, Package Name, Foreground Bytes, Foreground Bytes %%, "
74 "Foreground Fsync, Foreground Fsync %%, Background Bytes, Background Bytes %%, "
75 "Background Fsync, Background Fsync %%\n");
76 for (const auto& stat : data.topNWrites) {
77 StringAppendF(&buffer, "%" PRIu32 ", %s", stat.userId, stat.packageName.c_str());
78 for (int i = 0; i < UID_STATES; ++i) {
79 StringAppendF(&buffer, ", %" PRIu64 ", %.2f%%, %" PRIu64 ", %.2f%%", stat.bytes[i],
80 stat.bytesPercent[i], stat.fsync[i], stat.fsyncPercent[i]);
81 }
82 StringAppendF(&buffer, "\n");
83 }
84 return buffer;
85}
Lakshman Annadorai6094e9a2020-01-31 10:03:33 -080086
87Result<void> IoPerfCollection::start() {
88 Mutex::Autolock lock(mMutex);
89 if (mCurrCollectionEvent != CollectionEvent::NONE) {
90 return Error() << "Cannot start I/O performance collection more than once";
91 }
92 mCurrCollectionEvent = CollectionEvent::BOOT_TIME;
93
94 // TODO(b/148486340): Implement this method.
95 return Error() << "Unimplemented method";
96}
97
98Result<void> IoPerfCollection::onBootFinished() {
99 Mutex::Autolock lock(mMutex);
100 if (mCurrCollectionEvent != CollectionEvent::BOOT_TIME) {
101 return Error() << "Current collection event " << toEventString(mCurrCollectionEvent)
102 << " != " << toEventString(CollectionEvent::BOOT_TIME)
103 << " collection event";
104 }
105
106 // TODO(b/148486340): Implement this method.
107 return Error() << "Unimplemented method";
108}
109
110status_t IoPerfCollection::dump(int /*fd*/) {
111 Mutex::Autolock lock(mMutex);
112
113 // TODO(b/148486340): Implement this method.
Lakshman Annadoraiab4d3fd2020-02-06 11:24:56 -0800114
115 // TODO: Report when uidIoStats.enabled() returns false.
116
Lakshman Annadorai6094e9a2020-01-31 10:03:33 -0800117 return INVALID_OPERATION;
118}
119
120status_t IoPerfCollection::startCustomCollection(std::chrono::seconds /*interval*/,
121 std::chrono::seconds /*maxDuration*/) {
122 Mutex::Autolock lock(mMutex);
123 if (mCurrCollectionEvent != CollectionEvent::PERIODIC) {
124 ALOGE(
125 "Cannot start a custom collection when "
126 "the current collection event %s != %s collection event",
127 toEventString(mCurrCollectionEvent).c_str(),
128 toEventString(CollectionEvent::PERIODIC).c_str());
129 return INVALID_OPERATION;
130 }
131
132 // TODO(b/148486340): Implement this method.
133 return INVALID_OPERATION;
134}
135
136status_t IoPerfCollection::endCustomCollection(int /*fd*/) {
137 Mutex::Autolock lock(mMutex);
138 if (mCurrCollectionEvent != CollectionEvent::CUSTOM) {
139 ALOGE("No custom collection is running");
140 return INVALID_OPERATION;
141 }
142
143 // TODO(b/148486340): Implement this method.
Lakshman Annadoraiab4d3fd2020-02-06 11:24:56 -0800144
145 // TODO: Report when uidIoStats.enabled() returns false.
146
Lakshman Annadorai6094e9a2020-01-31 10:03:33 -0800147 return INVALID_OPERATION;
148}
149
150Result<void> IoPerfCollection::collect() {
151 Mutex::Autolock lock(mMutex);
152
153 // TODO(b/148486340): Implement this method.
154 return Error() << "Unimplemented method";
155}
156
Lakshman Annadoraiab4d3fd2020-02-06 11:24:56 -0800157Result<void> IoPerfCollection::collectUidIoPerfDataLocked(UidIoPerfData* uidIoPerfData) {
158 if (!mUidIoStats.enabled()) {
159 // Don't return an error to avoid log spamming on every collection. Instead, report this
160 // once in the generated dump.
161 return {};
162 }
163
164 const Result<std::unordered_map<uint32_t, UidIoUsage>>& usage = mUidIoStats.collect();
165 if (!usage) {
166 return Error() << "Failed to collect uid I/O usage: " << usage.error();
167 }
168
169 // Fetch only the top N reads and writes from the usage records.
170 UidIoUsage tempUsage = {};
171 std::vector<const UidIoUsage*> topNReads(mTopNStatsPerCategory, &tempUsage);
172 std::vector<const UidIoUsage*> topNWrites(mTopNStatsPerCategory, &tempUsage);
173 uint64_t total[METRIC_TYPES][UID_STATES] = {{0}};
174 std::unordered_set<uint32_t> unmappedUids;
175
176 for (const auto& uIt : *usage) {
177 const UidIoUsage& curUsage = uIt.second;
178 if (curUsage.ios.isZero()) {
179 continue;
180 }
181 if (mUidToPackageNameMapping.find(curUsage.uid) == mUidToPackageNameMapping.end()) {
182 unmappedUids.insert(curUsage.uid);
183 }
184 total[READ_BYTES][FOREGROUND] += curUsage.ios.metrics[READ_BYTES][FOREGROUND];
185 total[READ_BYTES][BACKGROUND] += curUsage.ios.metrics[READ_BYTES][BACKGROUND];
186 total[WRITE_BYTES][FOREGROUND] += curUsage.ios.metrics[WRITE_BYTES][FOREGROUND];
187 total[WRITE_BYTES][BACKGROUND] += curUsage.ios.metrics[WRITE_BYTES][BACKGROUND];
188 total[FSYNC_COUNT][FOREGROUND] += curUsage.ios.metrics[FSYNC_COUNT][FOREGROUND];
189 total[FSYNC_COUNT][BACKGROUND] += curUsage.ios.metrics[FSYNC_COUNT][BACKGROUND];
190
191 for (auto it = topNReads.begin(); it != topNReads.end(); ++it) {
192 const UidIoUsage* curRead = *it;
193 if (curRead->ios.sumReadBytes() > curUsage.ios.sumReadBytes()) {
194 continue;
195 }
196 topNReads.erase(topNReads.end() - 1);
197 topNReads.emplace(it, &curUsage);
198 break;
199 }
200 for (auto it = topNWrites.begin(); it != topNWrites.end(); ++it) {
201 const UidIoUsage* curWrite = *it;
202 if (curWrite->ios.sumWriteBytes() > curUsage.ios.sumWriteBytes()) {
203 continue;
204 }
205 topNWrites.erase(topNWrites.end() - 1);
206 topNWrites.emplace(it, &curUsage);
207 break;
208 }
209 }
210
211 const auto& ret = updateUidToPackageNameMapping(unmappedUids);
212 if (!ret) {
213 ALOGW("%s", ret.error().message().c_str());
214 }
215
216 // Convert the top N I/O usage to UidIoPerfData.
217 for (const auto& usage : topNReads) {
218 if (usage->ios.isZero()) {
219 // End of non-zero usage records. This case occurs when the number of UIDs with active
220 // I/O operations is < |kTopNStatsPerCategory|.
221 break;
222 }
223 struct UidIoPerfData::Stats stats = {
224 .userId = multiuser_get_user_id(usage->uid),
225 .packageName = std::to_string(usage->uid),
226 .bytes = {usage->ios.metrics[READ_BYTES][FOREGROUND],
227 usage->ios.metrics[READ_BYTES][BACKGROUND]},
228 .bytesPercent = {percentage(usage->ios.metrics[READ_BYTES][FOREGROUND],
229 total[READ_BYTES][FOREGROUND]),
230 percentage(usage->ios.metrics[READ_BYTES][BACKGROUND],
231 total[READ_BYTES][BACKGROUND])},
232 .fsync = {usage->ios.metrics[FSYNC_COUNT][FOREGROUND],
233 usage->ios.metrics[FSYNC_COUNT][BACKGROUND]},
234 .fsyncPercent = {percentage(usage->ios.metrics[FSYNC_COUNT][FOREGROUND],
235 total[FSYNC_COUNT][FOREGROUND]),
236 percentage(usage->ios.metrics[FSYNC_COUNT][BACKGROUND],
237 total[FSYNC_COUNT][BACKGROUND])},
238 };
239
240 if (mUidToPackageNameMapping.find(usage->uid) != mUidToPackageNameMapping.end()) {
241 stats.packageName = mUidToPackageNameMapping[usage->uid];
242 }
243
244 uidIoPerfData->topNReads.emplace_back(stats);
245 }
246
247 for (const auto& usage : topNWrites) {
248 if (usage->ios.isZero()) {
249 // End of non-zero usage records. This case occurs when the number of UIDs with active
250 // I/O operations is < |kTopNStatsPerCategory|.
251 break;
252 }
253 struct UidIoPerfData::Stats stats = {
254 .userId = multiuser_get_user_id(usage->uid),
255 .packageName = std::to_string(usage->uid),
256 .bytes = {usage->ios.metrics[WRITE_BYTES][FOREGROUND],
257 usage->ios.metrics[WRITE_BYTES][BACKGROUND]},
258 .bytesPercent = {percentage(usage->ios.metrics[WRITE_BYTES][FOREGROUND],
259 total[WRITE_BYTES][FOREGROUND]),
260 percentage(usage->ios.metrics[WRITE_BYTES][BACKGROUND],
261 total[WRITE_BYTES][BACKGROUND])},
262 .fsync = {usage->ios.metrics[FSYNC_COUNT][FOREGROUND],
263 usage->ios.metrics[FSYNC_COUNT][BACKGROUND]},
264 .fsyncPercent = {percentage(usage->ios.metrics[FSYNC_COUNT][FOREGROUND],
265 total[FSYNC_COUNT][FOREGROUND]),
266 percentage(usage->ios.metrics[FSYNC_COUNT][BACKGROUND],
267 total[FSYNC_COUNT][BACKGROUND])},
268 };
269
270 if (mUidToPackageNameMapping.find(usage->uid) != mUidToPackageNameMapping.end()) {
271 stats.packageName = mUidToPackageNameMapping[usage->uid];
272 }
273
274 uidIoPerfData->topNWrites.emplace_back(stats);
275 }
276 return {};
277}
278
279Result<void> IoPerfCollection::collectSystemIoPerfDataLocked(SystemIoPerfData* /*systemIoPerfData*/) {
Lakshman Annadorai6094e9a2020-01-31 10:03:33 -0800280 // TODO(b/148486340): Implement this method.
281 return Error() << "Unimplemented method";
282}
283
Lakshman Annadoraiab4d3fd2020-02-06 11:24:56 -0800284Result<void> IoPerfCollection::collectProcessIoPerfDataLocked(
285 ProcessIoPerfData* /*processIoPerfData*/) {
Lakshman Annadorai6094e9a2020-01-31 10:03:33 -0800286 // TODO(b/148486340): Implement this method.
287 return Error() << "Unimplemented method";
288}
289
Lakshman Annadoraiab4d3fd2020-02-06 11:24:56 -0800290Result<void> IoPerfCollection::updateUidToPackageNameMapping(
291 const std::unordered_set<uint32_t>& uids) {
292 std::vector<int32_t> appUids;
293
294 for (const auto& uid : uids) {
295 if (uid >= AID_APP_START) {
296 appUids.emplace_back(static_cast<int32_t>(uid));
297 continue;
298 }
299 // System/native UIDs.
300 passwd* usrpwd = getpwuid(uid);
301 if (!usrpwd) {
302 continue;
303 }
304 mUidToPackageNameMapping[uid] = std::string(usrpwd->pw_name);
305 }
306
307 if (appUids.empty()) {
308 return {};
309 }
310
311 if (mPackageManager == nullptr) {
312 auto ret = retrievePackageManager();
313 if (!ret) {
314 return Error() << "Failed to retrieve package manager: " << ret.error();
315 }
316 }
317
318 std::vector<std::string> packageNames;
319 const binder::Status& status = mPackageManager->getNamesForUids(appUids, &packageNames);
320 if (!status.isOk()) {
321 return Error() << "package_native::getNamesForUids failed: " << status.exceptionMessage();
322 }
323
324 for (uint32_t i = 0; i < appUids.size(); i++) {
325 if (!packageNames[i].empty()) {
326 mUidToPackageNameMapping[appUids[i]] = packageNames[i];
327 }
328 }
329
330 return {};
331}
332
333Result<void> IoPerfCollection::retrievePackageManager() {
334 const sp<IServiceManager> sm = defaultServiceManager();
335 if (sm == nullptr) {
336 return Error() << "Failed to retrieve defaultServiceManager";
337 }
338
339 sp<IBinder> binder = sm->getService(String16("package_native"));
340 if (binder == nullptr) {
341 return Error() << "Failed to get service package_native";
342 }
343 mPackageManager = interface_cast<IPackageManagerNative>(binder);
344 return {};
Lakshman Annadorai6094e9a2020-01-31 10:03:33 -0800345}
346
347} // namespace watchdog
348} // namespace automotive
349} // namespace android