1 /*
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 // STOPSHIP if true.
19
20 #include "IoOveruseMonitor.h"
21
22 #include "PackageInfoResolver.h"
23
24 #include <WatchdogProperties.sysprop.h>
25 #include <android-base/file.h>
26 #include <android/automotive/watchdog/internal/PackageIdentifier.h>
27 #include <android/automotive/watchdog/internal/UidType.h>
28 #include <binder/IPCThreadState.h>
29 #include <binder/Status.h>
30 #include <cutils/multiuser.h>
31 #include <log/log.h>
32 #include <processgroup/sched_policy.h>
33
34 #include <pthread.h>
35
36 #include <limits>
37 #include <thread> // NOLINT(build/c++11)
38
39 namespace android {
40 namespace automotive {
41 namespace watchdog {
42
43 using ::android::IPCThreadState;
44 using ::android::sp;
45 using ::android::automotive::watchdog::internal::ComponentType;
46 using ::android::automotive::watchdog::internal::IoOveruseConfiguration;
47 using ::android::automotive::watchdog::internal::PackageIdentifier;
48 using ::android::automotive::watchdog::internal::PackageInfo;
49 using ::android::automotive::watchdog::internal::PackageIoOveruseStats;
50 using ::android::automotive::watchdog::internal::PackageResourceOveruseAction;
51 using ::android::automotive::watchdog::internal::ResourceOveruseConfiguration;
52 using ::android::automotive::watchdog::internal::UidType;
53 using ::android::base::Error;
54 using ::android::base::Result;
55 using ::android::base::WriteStringToFd;
56 using ::android::binder::Status;
57
58 // Minimum written bytes to sync the stats with the Watchdog service.
59 constexpr int64_t kMinSyncWrittenBytes = 100 * 1024;
60 // Minimum percentage of threshold to warn killable applications.
61 constexpr double kDefaultIoOveruseWarnPercentage = 80;
62 // Maximum numer of system-wide stats (from periodic monitoring) to cache.
63 constexpr size_t kMaxPeriodicMonitorBufferSize = 1000;
64 constexpr const char* kHelpText =
65 "\n%s dump options:\n"
66 "%s <package name>, <package name>,...: Reset resource overuse stats for the given package "
67 "names. Value for this flag is a comma-separated value containing package names.\n";
68
69 namespace {
70
uniquePackageIdStr(const PackageIdentifier & id)71 std::string uniquePackageIdStr(const PackageIdentifier& id) {
72 return StringPrintf("%s:%" PRId32, id.name.c_str(), multiuser_get_user_id(id.uid));
73 }
74
diff(const PerStateBytes & lhs,const PerStateBytes & rhs)75 PerStateBytes diff(const PerStateBytes& lhs, const PerStateBytes& rhs) {
76 const auto sub = [](const int64_t& l, const int64_t& r) -> int64_t {
77 return l >= r ? (l - r) : 0;
78 };
79 PerStateBytes result;
80 result.foregroundBytes = sub(lhs.foregroundBytes, rhs.foregroundBytes);
81 result.backgroundBytes = sub(lhs.backgroundBytes, rhs.backgroundBytes);
82 result.garageModeBytes = sub(lhs.garageModeBytes, rhs.garageModeBytes);
83 return result;
84 }
85
calculateStartAndDuration(struct tm currentTm)86 std::tuple<int64_t, int64_t> calculateStartAndDuration(struct tm currentTm) {
87 // The stats are stored per-day so the start time is always the beginning of the day.
88 auto startTm = currentTm;
89 startTm.tm_sec = 0;
90 startTm.tm_min = 0;
91 startTm.tm_hour = 0;
92
93 int64_t startTime = static_cast<int64_t>(mktime(&startTm));
94 int64_t currentEpochSeconds = static_cast<int64_t>(mktime(¤tTm));
95 return std::make_tuple(startTime, currentEpochSeconds - startTime);
96 }
97
totalPerStateBytes(PerStateBytes perStateBytes)98 int64_t totalPerStateBytes(PerStateBytes perStateBytes) {
99 const auto sum = [](const int64_t& l, const int64_t& r) -> int64_t {
100 return std::numeric_limits<int64_t>::max() - l > r ? (l + r)
101 : std::numeric_limits<int64_t>::max();
102 };
103 return sum(perStateBytes.foregroundBytes,
104 sum(perStateBytes.backgroundBytes, perStateBytes.garageModeBytes));
105 }
106
107 } // namespace
108
calculateStartAndDuration(const time_t & currentTime)109 std::tuple<int64_t, int64_t> calculateStartAndDuration(const time_t& currentTime) {
110 struct tm currentGmt;
111 gmtime_r(¤tTime, ¤tGmt);
112 return calculateStartAndDuration(currentGmt);
113 }
114
IoOveruseMonitor(const android::sp<IWatchdogServiceHelper> & watchdogServiceHelper)115 IoOveruseMonitor::IoOveruseMonitor(
116 const android::sp<IWatchdogServiceHelper>& watchdogServiceHelper) :
117 mMinSyncWrittenBytes(kMinSyncWrittenBytes),
118 mWatchdogServiceHelper(watchdogServiceHelper),
119 mSystemWideWrittenBytes({}),
120 mPeriodicMonitorBufferSize(0),
121 mLastSystemWideIoMonitorTime(0),
122 mUserPackageDailyIoUsageById({}),
123 mIoOveruseWarnPercentage(0),
124 mLastUserPackageIoMonitorTime(0),
125 mOveruseListenersByUid({}),
126 mBinderDeathRecipient(sp<BinderDeathRecipient>::make(this)) {}
127
init()128 Result<void> IoOveruseMonitor::init() {
129 std::unique_lock writeLock(mRwMutex);
130 if (isInitializedLocked()) {
131 return Error() << "Cannot initialize " << name() << " more than once";
132 }
133 mPeriodicMonitorBufferSize = static_cast<size_t>(
134 sysprop::periodicMonitorBufferSize().value_or(kDefaultPeriodicMonitorBufferSize));
135 if (mPeriodicMonitorBufferSize == 0 ||
136 mPeriodicMonitorBufferSize > kMaxPeriodicMonitorBufferSize) {
137 return Error() << "Periodic monitor buffer size cannot be zero or above "
138 << kDefaultPeriodicMonitorBufferSize << ". Received "
139 << mPeriodicMonitorBufferSize;
140 }
141 mIoOveruseWarnPercentage = static_cast<double>(
142 sysprop::ioOveruseWarnPercentage().value_or(kDefaultIoOveruseWarnPercentage));
143 mIoOveruseConfigs = sp<IoOveruseConfigs>::make();
144 mPackageInfoResolver = PackageInfoResolver::getInstance();
145 mPackageInfoResolver->setPackageConfigurations(mIoOveruseConfigs->vendorPackagePrefixes(),
146 mIoOveruseConfigs->packagesToAppCategories());
147 if (DEBUG) {
148 ALOGD("Initialized %s data processor", name().c_str());
149 }
150 return {};
151 }
152
terminate()153 void IoOveruseMonitor::terminate() {
154 std::unique_lock writeLock(mRwMutex);
155
156 ALOGW("Terminating %s", name().c_str());
157 mWatchdogServiceHelper.clear();
158 mIoOveruseConfigs.clear();
159 mSystemWideWrittenBytes.clear();
160 mUserPackageDailyIoUsageById.clear();
161 for (const auto& [uid, listener] : mOveruseListenersByUid) {
162 BnResourceOveruseListener::asBinder(listener)->unlinkToDeath(mBinderDeathRecipient);
163 }
164 mBinderDeathRecipient.clear();
165 mOveruseListenersByUid.clear();
166 if (DEBUG) {
167 ALOGD("Terminated %s data processor", name().c_str());
168 }
169 return;
170 }
171
onPeriodicCollection(time_t time,SystemState systemState,const android::wp<UidIoStats> & uidIoStats,const android::wp<ProcStat> & procStat,const android::wp<ProcPidStat> & procPidStat)172 Result<void> IoOveruseMonitor::onPeriodicCollection(
173 time_t time, SystemState systemState, const android::wp<UidIoStats>& uidIoStats,
174 [[maybe_unused]] const android::wp<ProcStat>& procStat,
175 [[maybe_unused]] const android::wp<ProcPidStat>& procPidStat) {
176 if (uidIoStats == nullptr) {
177 return Error() << "Per-UID I/O stats collector must not be null";
178 }
179
180 std::unique_lock writeLock(mRwMutex);
181 struct tm prevGmt, curGmt;
182 gmtime_r(&mLastUserPackageIoMonitorTime, &prevGmt);
183 gmtime_r(&time, &curGmt);
184 if (prevGmt.tm_yday != curGmt.tm_yday || prevGmt.tm_year != curGmt.tm_year) {
185 /*
186 * Date changed so reset the daily I/O usage cache. CarWatchdogService automatically handles
187 * date change on |CarWatchdogService.latestIoOveruseStats| call.
188 */
189 mUserPackageDailyIoUsageById.clear();
190 }
191 mLastUserPackageIoMonitorTime = time;
192 const auto [startTime, durationInSeconds] = calculateStartAndDuration(curGmt);
193
194 auto perUidIoUsage = uidIoStats.promote()->deltaStats();
195 /*
196 * TODO(b/185849350): Maybe move the packageInfo fetching logic into UidIoStats module.
197 * This will also help avoid fetching package names in IoPerfCollection module.
198 */
199 std::vector<uid_t> seenUids;
200 for (auto it = perUidIoUsage.begin(); it != perUidIoUsage.end();) {
201 /*
202 * UidIoStats::deltaStats returns entries with zero write bytes because other metrics
203 * in these entries are non-zero.
204 */
205 if (it->second.ios.sumWriteBytes() == 0) {
206 it = perUidIoUsage.erase(it);
207 continue;
208 }
209 seenUids.push_back(it->first);
210 ++it;
211 }
212 if (perUidIoUsage.empty()) {
213 return {};
214 }
215 const auto packageInfosByUid = mPackageInfoResolver->getPackageInfosForUids(seenUids);
216 std::unordered_map<uid_t, IoOveruseStats> overusingNativeStats;
217 bool isGarageModeActive = systemState == SystemState::GARAGE_MODE;
218 for (const auto& [uid, uidIoStats] : perUidIoUsage) {
219 const auto& packageInfo = packageInfosByUid.find(uid);
220 if (packageInfo == packageInfosByUid.end()) {
221 continue;
222 }
223 UserPackageIoUsage curUsage(packageInfo->second, uidIoStats.ios, isGarageModeActive);
224 UserPackageIoUsage* dailyIoUsage;
225 if (auto cachedUsage = mUserPackageDailyIoUsageById.find(curUsage.id());
226 cachedUsage != mUserPackageDailyIoUsageById.end()) {
227 cachedUsage->second += curUsage;
228 dailyIoUsage = &cachedUsage->second;
229 } else {
230 const auto& [it, wasInserted] = mUserPackageDailyIoUsageById.insert(
231 std::pair(curUsage.id(), std::move(curUsage)));
232 dailyIoUsage = &it->second;
233 }
234
235 const auto threshold = mIoOveruseConfigs->fetchThreshold(dailyIoUsage->packageInfo);
236
237 PackageIoOveruseStats stats;
238 stats.uid = uid;
239 stats.shouldNotify = false;
240 stats.ioOveruseStats.startTime = startTime;
241 stats.ioOveruseStats.durationInSeconds = durationInSeconds;
242 stats.ioOveruseStats.writtenBytes = dailyIoUsage->writtenBytes;
243 stats.ioOveruseStats.totalOveruses = dailyIoUsage->totalOveruses;
244 stats.ioOveruseStats.remainingWriteBytes =
245 diff(threshold, diff(dailyIoUsage->writtenBytes, dailyIoUsage->forgivenWriteBytes));
246 stats.ioOveruseStats.killableOnOveruse =
247 mIoOveruseConfigs->isSafeToKill(dailyIoUsage->packageInfo);
248
249 const auto& remainingWriteBytes = stats.ioOveruseStats.remainingWriteBytes;
250 const auto exceedsWarnThreshold = [&](double remaining, double threshold) {
251 if (threshold == 0) {
252 return true;
253 }
254 double usedPercent = (100 - (remaining / threshold) * 100);
255 return usedPercent > mIoOveruseWarnPercentage;
256 };
257 bool shouldSyncWatchdogService =
258 (totalPerStateBytes(dailyIoUsage->writtenBytes) -
259 dailyIoUsage->lastSyncedWrittenBytes) >= mMinSyncWrittenBytes;
260 if (remainingWriteBytes.foregroundBytes == 0 || remainingWriteBytes.backgroundBytes == 0 ||
261 remainingWriteBytes.garageModeBytes == 0) {
262 stats.ioOveruseStats.totalOveruses = ++dailyIoUsage->totalOveruses;
263 /*
264 * Reset counters as the package may be disabled/killed by the watchdog service.
265 * NOTE: If this logic is updated, update watchdog service side logic as well.
266 */
267 dailyIoUsage->forgivenWriteBytes = dailyIoUsage->writtenBytes;
268 dailyIoUsage->isPackageWarned = false;
269 /*
270 * Send notifications for native service I/O overuses as well because system listeners
271 * need to be notified of all I/O overuses.
272 */
273 stats.shouldNotify = true;
274 if (dailyIoUsage->packageInfo.uidType == UidType::NATIVE) {
275 overusingNativeStats[uid] = stats.ioOveruseStats;
276 }
277 shouldSyncWatchdogService = true;
278 } else if (dailyIoUsage->packageInfo.uidType != UidType::NATIVE &&
279 stats.ioOveruseStats.killableOnOveruse && !dailyIoUsage->isPackageWarned &&
280 (exceedsWarnThreshold(remainingWriteBytes.foregroundBytes,
281 threshold.foregroundBytes) ||
282 exceedsWarnThreshold(remainingWriteBytes.backgroundBytes,
283 threshold.backgroundBytes) ||
284 exceedsWarnThreshold(remainingWriteBytes.garageModeBytes,
285 threshold.garageModeBytes))) {
286 /*
287 * No need to warn native services or applications that won't be killed on I/O overuse
288 * as they will be sent a notification when they exceed their daily threshold.
289 */
290 stats.shouldNotify = true;
291 // Avoid duplicate warning before the daily threshold exceeded notification is sent.
292 dailyIoUsage->isPackageWarned = true;
293 shouldSyncWatchdogService = true;
294 }
295 if (shouldSyncWatchdogService) {
296 dailyIoUsage->lastSyncedWrittenBytes = totalPerStateBytes(dailyIoUsage->writtenBytes);
297 mLatestIoOveruseStats.emplace_back(std::move(stats));
298 }
299 }
300 if (!overusingNativeStats.empty()) {
301 notifyNativePackagesLocked(overusingNativeStats);
302 }
303 if (mLatestIoOveruseStats.empty()) {
304 return {};
305 }
306 if (const auto status = mWatchdogServiceHelper->latestIoOveruseStats(mLatestIoOveruseStats);
307 !status.isOk()) {
308 // Don't clear the cache as it can be pushed again on the next collection.
309 ALOGW("Failed to push the latest I/O overuse stats to watchdog service: %s",
310 status.toString8().c_str());
311 } else {
312 mLatestIoOveruseStats.clear();
313 if (DEBUG) {
314 ALOGD("Pushed latest I/O overuse stats to watchdog service");
315 }
316 }
317 return {};
318 }
319
onCustomCollection(time_t time,SystemState systemState,const std::unordered_set<std::string> & filterPackages,const android::wp<UidIoStats> & uidIoStats,const android::wp<ProcStat> & procStat,const android::wp<ProcPidStat> & procPidStat)320 Result<void> IoOveruseMonitor::onCustomCollection(
321 time_t time, SystemState systemState,
322 [[maybe_unused]] const std::unordered_set<std::string>& filterPackages,
323 const android::wp<UidIoStats>& uidIoStats, const android::wp<ProcStat>& procStat,
324 const android::wp<ProcPidStat>& procPidStat) {
325 // Nothing special for custom collection.
326 return onPeriodicCollection(time, systemState, uidIoStats, procStat, procPidStat);
327 }
328
onPeriodicMonitor(time_t time,const android::wp<IProcDiskStatsInterface> & procDiskStats,const std::function<void ()> & alertHandler)329 Result<void> IoOveruseMonitor::onPeriodicMonitor(
330 time_t time, const android::wp<IProcDiskStatsInterface>& procDiskStats,
331 const std::function<void()>& alertHandler) {
332 if (procDiskStats == nullptr) {
333 return Error() << "Proc disk stats collector must not be null";
334 }
335
336 std::unique_lock writeLock(mRwMutex);
337 if (mLastSystemWideIoMonitorTime == 0) {
338 /*
339 * Do not record the first disk stats as it reflects the aggregated disks stats since the
340 * system boot up and is not in sync with the polling period. This will lead to spurious
341 * I/O overuse alerting.
342 */
343 mLastSystemWideIoMonitorTime = time;
344 return {};
345 }
346 const auto diskStats = procDiskStats.promote()->deltaSystemWideDiskStats();
347 mSystemWideWrittenBytes.push_back(
348 {.pollDurationInSecs = difftime(time, mLastSystemWideIoMonitorTime),
349 .bytesInKib = diskStats.numKibWritten});
350 for (const auto& threshold : mIoOveruseConfigs->systemWideAlertThresholds()) {
351 int64_t accountedWrittenKib = 0;
352 double accountedDurationInSecs = 0;
353 size_t accountedPolls = 0;
354 for (auto rit = mSystemWideWrittenBytes.rbegin(); rit != mSystemWideWrittenBytes.rend();
355 ++rit) {
356 accountedWrittenKib += rit->bytesInKib;
357 accountedDurationInSecs += rit->pollDurationInSecs;
358 ++accountedPolls;
359 if (accountedDurationInSecs >= threshold.durationInSeconds) {
360 break;
361 }
362 }
363 // Heuristic to handle spurious alerting when the buffer is partially filled.
364 if (const size_t bufferSize = mSystemWideWrittenBytes.size();
365 accountedPolls == bufferSize && bufferSize < mPeriodicMonitorBufferSize + 1 &&
366 threshold.durationInSeconds > accountedDurationInSecs) {
367 continue;
368 }
369 const double thresholdKbps = threshold.writtenBytesPerSecond / 1024.0;
370 if (const auto kbps = accountedWrittenKib / accountedDurationInSecs;
371 kbps >= thresholdKbps) {
372 alertHandler();
373 break;
374 }
375 }
376 if (mSystemWideWrittenBytes.size() > mPeriodicMonitorBufferSize) {
377 mSystemWideWrittenBytes.erase(mSystemWideWrittenBytes.begin()); // Erase the oldest entry.
378 }
379 mLastSystemWideIoMonitorTime = time;
380 return {};
381 }
382
onDump(int fd)383 Result<void> IoOveruseMonitor::onDump([[maybe_unused]] int fd) {
384 // TODO(b/183436216): Dump the list of killed/disabled packages. Dump the list of packages that
385 // exceed xx% of their threshold.
386 return {};
387 }
388
dumpHelpText(int fd)389 bool IoOveruseMonitor::dumpHelpText(int fd) {
390 return WriteStringToFd(StringPrintf(kHelpText, name().c_str(), kResetResourceOveruseStatsFlag),
391 fd);
392 }
393
notifyNativePackagesLocked(const std::unordered_map<uid_t,IoOveruseStats> & statsByUid)394 void IoOveruseMonitor::notifyNativePackagesLocked(
395 const std::unordered_map<uid_t, IoOveruseStats>& statsByUid) {
396 for (const auto& [uid, ioOveruseStats] : statsByUid) {
397 IResourceOveruseListener* listener;
398 if (const auto it = mOveruseListenersByUid.find(uid); it == mOveruseListenersByUid.end()) {
399 continue;
400 } else {
401 listener = it->second.get();
402 }
403 ResourceOveruseStats stats;
404 stats.set<ResourceOveruseStats::ioOveruseStats>(ioOveruseStats);
405 listener->onOveruse(stats);
406 }
407 if (DEBUG) {
408 ALOGD("Notified native packages on I/O overuse");
409 }
410 // TODO(b/184310189): Upload I/O overuse metrics for native packages.
411 }
412
updateResourceOveruseConfigurations(const std::vector<ResourceOveruseConfiguration> & configs)413 Result<void> IoOveruseMonitor::updateResourceOveruseConfigurations(
414 const std::vector<ResourceOveruseConfiguration>& configs) {
415 std::unique_lock writeLock(mRwMutex);
416 if (!isInitializedLocked()) {
417 return Error(Status::EX_ILLEGAL_STATE) << name() << " is not initialized";
418 }
419 if (const auto result = mIoOveruseConfigs->update(configs); !result.ok()) {
420 return result;
421 }
422 std::thread writeToDiskThread([&]() {
423 if (set_sched_policy(0, SP_BACKGROUND) != 0) {
424 ALOGW("Failed to set background scheduling priority for writing resource overuse "
425 "configs to disk");
426 }
427 if (int result = pthread_setname_np(pthread_self(), "ResOveruseCfgWr"); result != 0) {
428 ALOGE("Failed to set thread name to 'ResOveruseCfgWr'");
429 }
430 std::unique_lock writeLock(mRwMutex);
431 if (const auto result = mIoOveruseConfigs->writeToDisk(); !result.ok()) {
432 ALOGE("Failed to write resource overuse configs to disk: %s",
433 result.error().message().c_str());
434 }
435 });
436 writeToDiskThread.detach();
437 return {};
438 }
439
getResourceOveruseConfigurations(std::vector<ResourceOveruseConfiguration> * configs)440 Result<void> IoOveruseMonitor::getResourceOveruseConfigurations(
441 std::vector<ResourceOveruseConfiguration>* configs) {
442 std::shared_lock readLock(mRwMutex);
443 if (!isInitializedLocked()) {
444 return Error(Status::EX_ILLEGAL_STATE) << name() << " is not initialized";
445 }
446 mIoOveruseConfigs->get(configs);
447 return {};
448 }
449
actionTakenOnIoOveruse(const std::vector<PackageResourceOveruseAction> & actions)450 Result<void> IoOveruseMonitor::actionTakenOnIoOveruse(
451 [[maybe_unused]] const std::vector<PackageResourceOveruseAction>& actions) {
452 // TODO(b/184310189): Upload metrics.
453 if (DEBUG) {
454 ALOGD("Recorded action taken on I/O overuse");
455 }
456 return {};
457 }
458
addIoOveruseListener(const sp<IResourceOveruseListener> & listener)459 Result<void> IoOveruseMonitor::addIoOveruseListener(const sp<IResourceOveruseListener>& listener) {
460 pid_t callingPid = IPCThreadState::self()->getCallingPid();
461 uid_t callingUid = IPCThreadState::self()->getCallingUid();
462 std::unique_lock writeLock(mRwMutex);
463 auto binder = BnResourceOveruseListener::asBinder(listener);
464 if (findListenerAndProcessLocked(binder, nullptr)) {
465 ALOGW("Failed to register the I/O overuse listener (pid: %d, uid: %d) as it is already "
466 "registered",
467 callingPid, callingUid);
468 return {};
469 }
470 if (const auto status = binder->linkToDeath(mBinderDeathRecipient); status != OK) {
471 return Error(Status::EX_ILLEGAL_STATE)
472 << "(pid " << callingPid << ", uid: " << callingUid << ") is dead";
473 }
474 mOveruseListenersByUid[callingUid] = listener;
475 if (DEBUG) {
476 ALOGD("Added I/O overuse listener for uid: %d", callingUid);
477 }
478 return {};
479 }
480
removeIoOveruseListener(const sp<IResourceOveruseListener> & listener)481 Result<void> IoOveruseMonitor::removeIoOveruseListener(
482 const sp<IResourceOveruseListener>& listener) {
483 std::unique_lock writeLock(mRwMutex);
484 const auto processor = [&](ListenersByUidMap& listeners, ListenersByUidMap::const_iterator it) {
485 auto binder = BnResourceOveruseListener::asBinder(it->second);
486 binder->unlinkToDeath(mBinderDeathRecipient);
487 listeners.erase(it);
488 };
489 if (const auto binder = BnResourceOveruseListener::asBinder(listener);
490 !findListenerAndProcessLocked(binder, processor)) {
491 return Error(Status::EX_ILLEGAL_ARGUMENT) << "Listener is not previously registered";
492 }
493 if (DEBUG) {
494 ALOGD("Removed I/O overuse listener for uid: %d", IPCThreadState::self()->getCallingUid());
495 }
496 return {};
497 }
498
getIoOveruseStats(IoOveruseStats * ioOveruseStats)499 Result<void> IoOveruseMonitor::getIoOveruseStats(IoOveruseStats* ioOveruseStats) {
500 if (!isInitialized()) {
501 return Error(Status::EX_ILLEGAL_STATE) << "I/O overuse monitor is not initialized";
502 }
503 uid_t callingUid = IPCThreadState::self()->getCallingUid();
504 const auto packageInfosByUid = mPackageInfoResolver->getPackageInfosForUids({callingUid});
505 const PackageInfo* packageInfo;
506 if (const auto it = packageInfosByUid.find(callingUid); it == packageInfosByUid.end()) {
507 return Error(Status::EX_ILLEGAL_ARGUMENT)
508 << "Package information not available for calling UID(" << callingUid << ")";
509 } else {
510 packageInfo = &it->second;
511 }
512 std::shared_lock readLock(mRwMutex);
513 const UserPackageIoUsage* dailyIoUsage;
514 if (const auto it = mUserPackageDailyIoUsageById.find(
515 uniquePackageIdStr(packageInfo->packageIdentifier));
516 it == mUserPackageDailyIoUsageById.end()) {
517 return Error(Status::EX_ILLEGAL_ARGUMENT)
518 << "Calling UID " << callingUid << " doesn't have I/O overuse stats";
519 } else {
520 dailyIoUsage = &it->second;
521 }
522 ioOveruseStats->killableOnOveruse = mIoOveruseConfigs->isSafeToKill(*packageInfo);
523 const auto thresholdBytes = mIoOveruseConfigs->fetchThreshold(*packageInfo);
524 ioOveruseStats->remainingWriteBytes =
525 diff(thresholdBytes,
526 diff(dailyIoUsage->writtenBytes, dailyIoUsage->forgivenWriteBytes));
527 ioOveruseStats->totalOveruses = dailyIoUsage->totalOveruses;
528 ioOveruseStats->writtenBytes = dailyIoUsage->writtenBytes;
529 const auto [startTime, durationInSeconds] =
530 calculateStartAndDuration(mLastUserPackageIoMonitorTime);
531 ioOveruseStats->startTime = startTime;
532 ioOveruseStats->durationInSeconds = durationInSeconds;
533 if (DEBUG) {
534 ALOGD("Returning I/O overuse stats for uid: %d", callingUid);
535 }
536 return {};
537 }
538
resetIoOveruseStats(const std::vector<std::string> & packageNames)539 Result<void> IoOveruseMonitor::resetIoOveruseStats(const std::vector<std::string>& packageNames) {
540 if (const auto status = mWatchdogServiceHelper->resetResourceOveruseStats(packageNames);
541 !status.isOk()) {
542 return Error() << "Failed to reset stats in watchdog service: " << status.toString8();
543 }
544 std::unordered_set<std::string> uniquePackageNames;
545 std::copy(packageNames.begin(), packageNames.end(),
546 std::inserter(uniquePackageNames, uniquePackageNames.end()));
547 for (auto& [key, usage] : mUserPackageDailyIoUsageById) {
548 if (uniquePackageNames.find(usage.packageInfo.packageIdentifier.name) !=
549 uniquePackageNames.end()) {
550 usage.resetStats();
551 }
552 }
553 return {};
554 }
555
handleBinderDeath(const wp<IBinder> & who)556 void IoOveruseMonitor::handleBinderDeath(const wp<IBinder>& who) {
557 std::unique_lock writeLock(mRwMutex);
558 IBinder* binder = who.unsafe_get();
559 findListenerAndProcessLocked(binder,
560 [&](ListenersByUidMap& listeners,
561 ListenersByUidMap::const_iterator it) {
562 ALOGW("Resource overuse notification handler died for uid(%d)",
563 it->first);
564 listeners.erase(it);
565 });
566 }
567
findListenerAndProcessLocked(const sp<IBinder> & binder,const Processor & processor)568 bool IoOveruseMonitor::findListenerAndProcessLocked(const sp<IBinder>& binder,
569 const Processor& processor) {
570 for (auto it = mOveruseListenersByUid.begin(); it != mOveruseListenersByUid.end(); ++it) {
571 if (BnResourceOveruseListener::asBinder(it->second) != binder) {
572 continue;
573 }
574 if (processor != nullptr) {
575 processor(mOveruseListenersByUid, it);
576 }
577 return true;
578 }
579 return false;
580 }
581
UserPackageIoUsage(const PackageInfo & pkgInfo,const IoUsage & ioUsage,const bool isGarageModeActive)582 IoOveruseMonitor::UserPackageIoUsage::UserPackageIoUsage(const PackageInfo& pkgInfo,
583 const IoUsage& ioUsage,
584 const bool isGarageModeActive) {
585 packageInfo = pkgInfo;
586 if (isGarageModeActive) {
587 writtenBytes.garageModeBytes = ioUsage.sumWriteBytes();
588 } else {
589 writtenBytes.foregroundBytes = ioUsage.metrics[WRITE_BYTES][FOREGROUND];
590 writtenBytes.backgroundBytes = ioUsage.metrics[WRITE_BYTES][BACKGROUND];
591 }
592 }
593
operator +=(const UserPackageIoUsage & r)594 IoOveruseMonitor::UserPackageIoUsage& IoOveruseMonitor::UserPackageIoUsage::operator+=(
595 const UserPackageIoUsage& r) {
596 if (id() == r.id()) {
597 packageInfo = r.packageInfo;
598 }
599 const auto sum = [](const int64_t& l, const int64_t& r) -> int64_t {
600 return (std::numeric_limits<int64_t>::max() - l) > r ? (l + r)
601 : std::numeric_limits<int64_t>::max();
602 };
603 writtenBytes.foregroundBytes =
604 sum(writtenBytes.foregroundBytes, r.writtenBytes.foregroundBytes);
605 writtenBytes.backgroundBytes =
606 sum(writtenBytes.backgroundBytes, r.writtenBytes.backgroundBytes);
607 writtenBytes.garageModeBytes =
608 sum(writtenBytes.garageModeBytes, r.writtenBytes.garageModeBytes);
609
610 return *this;
611 }
612
id() const613 const std::string IoOveruseMonitor::UserPackageIoUsage::id() const {
614 return uniquePackageIdStr(packageInfo.packageIdentifier);
615 }
616
resetStats()617 void IoOveruseMonitor::UserPackageIoUsage::resetStats() {
618 writtenBytes = {};
619 forgivenWriteBytes = {};
620 totalOveruses = 0;
621 isPackageWarned = false;
622 lastSyncedWrittenBytes = 0;
623 }
624
625 } // namespace watchdog
626 } // namespace automotive
627 } // namespace android
628