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-base/strings.h>
27 #include <android/automotive/watchdog/internal/PackageIdentifier.h>
28 #include <android/automotive/watchdog/internal/UidType.h>
29 #include <binder/IPCThreadState.h>
30 #include <binder/Status.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 namespace {
44
45 using ::android::IPCThreadState;
46 using ::android::sp;
47 using ::android::automotive::watchdog::internal::ComponentType;
48 using ::android::automotive::watchdog::internal::IoOveruseConfiguration;
49 using ::android::automotive::watchdog::internal::IoUsageStats;
50 using ::android::automotive::watchdog::internal::PackageIdentifier;
51 using ::android::automotive::watchdog::internal::PackageInfo;
52 using ::android::automotive::watchdog::internal::PackageIoOveruseStats;
53 using ::android::automotive::watchdog::internal::ResourceOveruseConfiguration;
54 using ::android::automotive::watchdog::internal::UidType;
55 using ::android::automotive::watchdog::internal::UserPackageIoUsageStats;
56 using ::android::base::EndsWith;
57 using ::android::base::Error;
58 using ::android::base::Result;
59 using ::android::base::StringPrintf;
60 using ::android::base::WriteStringToFd;
61 using ::android::binder::Status;
62
63 constexpr int64_t kMaxInt32 = std::numeric_limits<int32_t>::max();
64 constexpr int64_t kMaxInt64 = std::numeric_limits<int64_t>::max();
65 // Minimum written bytes to sync the stats with the Watchdog service.
66 constexpr int64_t kMinSyncWrittenBytes = 100 * 1024;
67 // Minimum percentage of threshold to warn killable applications.
68 constexpr double kDefaultIoOveruseWarnPercentage = 80;
69 // Maximum numer of system-wide stats (from periodic monitoring) to cache.
70 constexpr size_t kMaxPeriodicMonitorBufferSize = 1000;
71 constexpr const char* kHelpText =
72 "\n%s dump options:\n"
73 "%s <package name>, <package name>,...: Reset resource overuse stats for the given package "
74 "names. Value for this flag is a comma-separated value containing package names.\n";
75
uniquePackageIdStr(const std::string & name,userid_t userId)76 std::string uniquePackageIdStr(const std::string& name, userid_t userId) {
77 return StringPrintf("%s:%" PRId32, name.c_str(), userId);
78 }
79
uniquePackageIdStr(const PackageIdentifier & id)80 std::string uniquePackageIdStr(const PackageIdentifier& id) {
81 return uniquePackageIdStr(id.name, multiuser_get_user_id(id.uid));
82 }
83
sum(const PerStateBytes & lhs,const PerStateBytes & rhs)84 PerStateBytes sum(const PerStateBytes& lhs, const PerStateBytes& rhs) {
85 const auto sum = [](const int64_t& l, const int64_t& r) -> int64_t {
86 return (kMaxInt64 - l) > r ? (l + r) : kMaxInt64;
87 };
88 PerStateBytes result;
89 result.foregroundBytes = sum(lhs.foregroundBytes, rhs.foregroundBytes);
90 result.backgroundBytes = sum(lhs.backgroundBytes, rhs.backgroundBytes);
91 result.garageModeBytes = sum(lhs.garageModeBytes, rhs.garageModeBytes);
92 return result;
93 }
94
diff(const PerStateBytes & lhs,const PerStateBytes & rhs)95 PerStateBytes diff(const PerStateBytes& lhs, const PerStateBytes& rhs) {
96 const auto sub = [](const int64_t& l, const int64_t& r) -> int64_t {
97 return l >= r ? (l - r) : 0;
98 };
99 PerStateBytes result;
100 result.foregroundBytes = sub(lhs.foregroundBytes, rhs.foregroundBytes);
101 result.backgroundBytes = sub(lhs.backgroundBytes, rhs.backgroundBytes);
102 result.garageModeBytes = sub(lhs.garageModeBytes, rhs.garageModeBytes);
103 return result;
104 }
105
calculateStartAndDuration(struct tm currentTm)106 std::tuple<int64_t, int64_t> calculateStartAndDuration(struct tm currentTm) {
107 // The stats are stored per-day so the start time is always the beginning of the day.
108 auto startTm = currentTm;
109 startTm.tm_sec = 0;
110 startTm.tm_min = 0;
111 startTm.tm_hour = 0;
112
113 int64_t startTime = static_cast<int64_t>(mktime(&startTm));
114 int64_t currentEpochSeconds = static_cast<int64_t>(mktime(¤tTm));
115 return std::make_tuple(startTime, currentEpochSeconds - startTime);
116 }
117
totalPerStateBytes(PerStateBytes perStateBytes)118 int64_t totalPerStateBytes(PerStateBytes perStateBytes) {
119 const auto sum = [](const int64_t& l, const int64_t& r) -> int64_t {
120 return kMaxInt64 - l > r ? (l + r) : kMaxInt64;
121 };
122 return sum(perStateBytes.foregroundBytes,
123 sum(perStateBytes.backgroundBytes, perStateBytes.garageModeBytes));
124 }
125
calculateOveruseAndForgivenBytes(PerStateBytes writtenBytes,PerStateBytes threshold)126 std::tuple<int32_t, PerStateBytes> calculateOveruseAndForgivenBytes(PerStateBytes writtenBytes,
127 PerStateBytes threshold) {
128 const auto div = [](const int64_t& l, const int64_t& r) -> int32_t {
129 return r > 0 ? (l / r) : 1;
130 };
131 const auto mul = [](const int32_t& l, const int32_t& r) -> int32_t {
132 if (l == 0 || r == 0) {
133 return 0;
134 }
135 return (kMaxInt32 / r) > l ? (l * r) : kMaxInt32;
136 };
137 const auto sum = [](const int32_t& l, const int32_t& r) -> int32_t {
138 return (kMaxInt32 - l) > r ? (l + r) : kMaxInt32;
139 };
140 int32_t foregroundOveruses = div(writtenBytes.foregroundBytes, threshold.foregroundBytes);
141 int32_t backgroundOveruses = div(writtenBytes.backgroundBytes, threshold.backgroundBytes);
142 int32_t garageModeOveruses = div(writtenBytes.garageModeBytes, threshold.garageModeBytes);
143 int32_t totalOveruses = sum(foregroundOveruses, sum(backgroundOveruses, garageModeOveruses));
144
145 PerStateBytes forgivenWriteBytes;
146 forgivenWriteBytes.foregroundBytes = mul(foregroundOveruses, threshold.foregroundBytes);
147 forgivenWriteBytes.backgroundBytes = mul(backgroundOveruses, threshold.backgroundBytes);
148 forgivenWriteBytes.garageModeBytes = mul(garageModeOveruses, threshold.garageModeBytes);
149
150 return std::make_tuple(totalOveruses, forgivenWriteBytes);
151 }
152
153 } // namespace
154
calculateStartAndDuration(const time_t & currentTime)155 std::tuple<int64_t, int64_t> calculateStartAndDuration(const time_t& currentTime) {
156 struct tm currentGmt;
157 gmtime_r(¤tTime, ¤tGmt);
158 return calculateStartAndDuration(currentGmt);
159 }
160
IoOveruseMonitor(const android::sp<WatchdogServiceHelperInterface> & watchdogServiceHelper)161 IoOveruseMonitor::IoOveruseMonitor(
162 const android::sp<WatchdogServiceHelperInterface>& watchdogServiceHelper) :
163 mMinSyncWrittenBytes(kMinSyncWrittenBytes),
164 mWatchdogServiceHelper(watchdogServiceHelper),
165 mDidReadTodayPrevBootStats(false),
166 mSystemWideWrittenBytes({}),
167 mPeriodicMonitorBufferSize(0),
168 mLastSystemWideIoMonitorTime(0),
169 mUserPackageDailyIoUsageById({}),
170 mIoOveruseWarnPercentage(0),
171 mLastUserPackageIoMonitorTime(0),
172 mOveruseListenersByUid({}) {}
173
init()174 Result<void> IoOveruseMonitor::init() {
175 std::unique_lock writeLock(mRwMutex);
176 if (isInitializedLocked()) {
177 return Error() << "Cannot initialize " << name() << " more than once";
178 }
179 mPeriodicMonitorBufferSize = static_cast<size_t>(
180 sysprop::periodicMonitorBufferSize().value_or(kDefaultPeriodicMonitorBufferSize));
181 if (mPeriodicMonitorBufferSize == 0 ||
182 mPeriodicMonitorBufferSize > kMaxPeriodicMonitorBufferSize) {
183 return Error() << "Periodic monitor buffer size cannot be zero or above "
184 << kDefaultPeriodicMonitorBufferSize << ". Received "
185 << mPeriodicMonitorBufferSize;
186 }
187 mBinderDeathRecipient =
188 sp<BinderDeathRecipient>::make(sp<IoOveruseMonitor>::fromExisting(this));
189 mIoOveruseWarnPercentage = static_cast<double>(
190 sysprop::ioOveruseWarnPercentage().value_or(kDefaultIoOveruseWarnPercentage));
191 mIoOveruseConfigs = sp<IoOveruseConfigs>::make();
192 mPackageInfoResolver = PackageInfoResolver::getInstance();
193 mPackageInfoResolver->setPackageConfigurations(mIoOveruseConfigs->vendorPackagePrefixes(),
194 mIoOveruseConfigs->packagesToAppCategories());
195 if (DEBUG) {
196 ALOGD("Initialized %s data processor", name().c_str());
197 }
198 return {};
199 }
200
terminate()201 void IoOveruseMonitor::terminate() {
202 std::unique_lock writeLock(mRwMutex);
203
204 ALOGW("Terminating %s", name().c_str());
205 mWatchdogServiceHelper.clear();
206 mIoOveruseConfigs.clear();
207 mSystemWideWrittenBytes.clear();
208 mUserPackageDailyIoUsageById.clear();
209 for (const auto& [uid, listener] : mOveruseListenersByUid) {
210 BnResourceOveruseListener::asBinder(listener)->unlinkToDeath(mBinderDeathRecipient);
211 }
212 mBinderDeathRecipient.clear();
213 mOveruseListenersByUid.clear();
214 if (DEBUG) {
215 ALOGD("Terminated %s data processor", name().c_str());
216 }
217 return;
218 }
219
onPeriodicCollection(time_t time,SystemState systemState,const android::wp<UidStatsCollectorInterface> & uidStatsCollector,const android::wp<ProcStatCollectorInterface> & procStatCollector)220 Result<void> IoOveruseMonitor::onPeriodicCollection(
221 time_t time, SystemState systemState,
222 const android::wp<UidStatsCollectorInterface>& uidStatsCollector,
223 [[maybe_unused]] const android::wp<ProcStatCollectorInterface>& procStatCollector) {
224 android::sp<UidStatsCollectorInterface> uidStatsCollectorSp = uidStatsCollector.promote();
225 if (uidStatsCollectorSp == nullptr) {
226 return Error() << "Per-UID I/O stats collector must not be null";
227 }
228
229 std::unique_lock writeLock(mRwMutex);
230 if (!mDidReadTodayPrevBootStats) {
231 syncTodayIoUsageStatsLocked();
232 }
233 struct tm prevGmt, curGmt;
234 gmtime_r(&mLastUserPackageIoMonitorTime, &prevGmt);
235 gmtime_r(&time, &curGmt);
236 if (prevGmt.tm_yday != curGmt.tm_yday || prevGmt.tm_year != curGmt.tm_year) {
237 /*
238 * Date changed so reset the daily I/O usage cache. CarWatchdogService automatically handles
239 * date change on |CarWatchdogService.latestIoOveruseStats| call.
240 */
241 mUserPackageDailyIoUsageById.clear();
242 }
243 mLastUserPackageIoMonitorTime = time;
244 const auto [startTime, durationInSeconds] = calculateStartAndDuration(curGmt);
245
246 auto uidStats = uidStatsCollectorSp->deltaStats();
247 if (uidStats.empty()) {
248 return {};
249 }
250 std::unordered_map<uid_t, IoOveruseStats> overusingNativeStats;
251 bool isGarageModeActive = systemState == SystemState::GARAGE_MODE;
252 for (const auto& curUidStats : uidStats) {
253 if (curUidStats.ioStats.sumWriteBytes() == 0 || !curUidStats.hasPackageInfo()) {
254 /* 1. Ignore UIDs with zero written bytes since the last collection because they are
255 * either already accounted for or no writes made since system start.
256 *
257 * 2. UID stats without package info is not useful because the stats isn't attributed to
258 * any package/service.
259 */
260 continue;
261 }
262 UserPackageIoUsage curUsage(curUidStats.packageInfo, curUidStats.ioStats,
263 isGarageModeActive);
264 UserPackageIoUsage* dailyIoUsage;
265 if (auto cachedUsage = mUserPackageDailyIoUsageById.find(curUsage.id());
266 cachedUsage != mUserPackageDailyIoUsageById.end()) {
267 cachedUsage->second += curUsage;
268 dailyIoUsage = &cachedUsage->second;
269 } else {
270 if (auto prevBootStats = mPrevBootIoUsageStatsById.find(curUsage.id());
271 prevBootStats != mPrevBootIoUsageStatsById.end()) {
272 curUsage += prevBootStats->second;
273 mPrevBootIoUsageStatsById.erase(prevBootStats);
274 }
275 const auto& [it, wasInserted] = mUserPackageDailyIoUsageById.insert(
276 std::pair(curUsage.id(), std::move(curUsage)));
277 dailyIoUsage = &it->second;
278 }
279
280 const auto threshold = mIoOveruseConfigs->fetchThreshold(dailyIoUsage->packageInfo);
281
282 const auto deltaWrittenBytes =
283 diff(dailyIoUsage->writtenBytes, dailyIoUsage->forgivenWriteBytes);
284 const auto [currentOveruses, forgivenWriteBytes] =
285 calculateOveruseAndForgivenBytes(deltaWrittenBytes, threshold);
286 dailyIoUsage->totalOveruses += currentOveruses;
287 dailyIoUsage->forgivenWriteBytes =
288 sum(dailyIoUsage->forgivenWriteBytes, forgivenWriteBytes);
289
290 PackageIoOveruseStats stats;
291 stats.uid = curUidStats.packageInfo.packageIdentifier.uid;
292 stats.shouldNotify = false;
293 stats.forgivenWriteBytes = dailyIoUsage->forgivenWriteBytes;
294 stats.ioOveruseStats.startTime = startTime;
295 stats.ioOveruseStats.durationInSeconds = durationInSeconds;
296 stats.ioOveruseStats.writtenBytes = dailyIoUsage->writtenBytes;
297 stats.ioOveruseStats.totalOveruses = dailyIoUsage->totalOveruses;
298 stats.ioOveruseStats.remainingWriteBytes = diff(threshold, deltaWrittenBytes);
299 stats.ioOveruseStats.killableOnOveruse =
300 mIoOveruseConfigs->isSafeToKill(dailyIoUsage->packageInfo);
301
302 const auto& remainingWriteBytes = stats.ioOveruseStats.remainingWriteBytes;
303 const auto exceedsWarnThreshold = [&](double remaining, double threshold) {
304 if (threshold == 0) {
305 return true;
306 }
307 double usedPercent = (100 - (remaining / threshold) * 100);
308 return usedPercent > mIoOveruseWarnPercentage;
309 };
310 bool shouldSyncWatchdogService =
311 (totalPerStateBytes(dailyIoUsage->writtenBytes) -
312 dailyIoUsage->lastSyncedWrittenBytes) >= mMinSyncWrittenBytes;
313 if (currentOveruses > 0) {
314 dailyIoUsage->isPackageWarned = false;
315 /*
316 * Send notifications for native service I/O overuses as well because system listeners
317 * need to be notified of all I/O overuses.
318 */
319 stats.shouldNotify = true;
320 if (dailyIoUsage->packageInfo.uidType == UidType::NATIVE) {
321 overusingNativeStats[stats.uid] = stats.ioOveruseStats;
322 }
323 shouldSyncWatchdogService = true;
324 } else if (dailyIoUsage->packageInfo.uidType == UidType::APPLICATION &&
325 stats.ioOveruseStats.killableOnOveruse && !dailyIoUsage->isPackageWarned &&
326 (exceedsWarnThreshold(remainingWriteBytes.foregroundBytes,
327 threshold.foregroundBytes) ||
328 exceedsWarnThreshold(remainingWriteBytes.backgroundBytes,
329 threshold.backgroundBytes) ||
330 exceedsWarnThreshold(remainingWriteBytes.garageModeBytes,
331 threshold.garageModeBytes))) {
332 /*
333 * No need to warn native services or applications that won't be killed on I/O overuse
334 * as they will be sent a notification when they exceed their daily threshold.
335 */
336 stats.shouldNotify = true;
337 // Avoid duplicate warning before the daily threshold exceeded notification is sent.
338 dailyIoUsage->isPackageWarned = true;
339 shouldSyncWatchdogService = true;
340 }
341 if (shouldSyncWatchdogService) {
342 dailyIoUsage->lastSyncedWrittenBytes = totalPerStateBytes(dailyIoUsage->writtenBytes);
343 mLatestIoOveruseStats.emplace_back(std::move(stats));
344 }
345 }
346 if (!overusingNativeStats.empty()) {
347 notifyNativePackagesLocked(overusingNativeStats);
348 }
349 if (mLatestIoOveruseStats.empty()) {
350 return {};
351 }
352 if (const auto status = mWatchdogServiceHelper->latestIoOveruseStats(mLatestIoOveruseStats);
353 !status.isOk()) {
354 // Don't clear the cache as it can be pushed again on the next collection.
355 ALOGW("Failed to push the latest I/O overuse stats to watchdog service: %s",
356 status.toString8().c_str());
357 } else {
358 mLatestIoOveruseStats.clear();
359 if (DEBUG) {
360 ALOGD("Pushed latest I/O overuse stats to watchdog service");
361 }
362 }
363 return {};
364 }
365
onCustomCollection(time_t time,SystemState systemState,const std::unordered_set<std::string> & filterPackages,const android::wp<UidStatsCollectorInterface> & uidStatsCollector,const android::wp<ProcStatCollectorInterface> & procStatCollector)366 Result<void> IoOveruseMonitor::onCustomCollection(
367 time_t time, SystemState systemState,
368 [[maybe_unused]] const std::unordered_set<std::string>& filterPackages,
369 const android::wp<UidStatsCollectorInterface>& uidStatsCollector,
370 const android::wp<ProcStatCollectorInterface>& procStatCollector) {
371 // Nothing special for custom collection.
372 return onPeriodicCollection(time, systemState, uidStatsCollector, procStatCollector);
373 }
374
onPeriodicMonitor(time_t time,const android::wp<ProcDiskStatsCollectorInterface> & procDiskStatsCollector,const std::function<void ()> & alertHandler)375 Result<void> IoOveruseMonitor::onPeriodicMonitor(
376 time_t time, const android::wp<ProcDiskStatsCollectorInterface>& procDiskStatsCollector,
377 const std::function<void()>& alertHandler) {
378 if (procDiskStatsCollector == nullptr) {
379 return Error() << "Proc disk stats collector must not be null";
380 }
381
382 std::unique_lock writeLock(mRwMutex);
383 if (mLastSystemWideIoMonitorTime == 0) {
384 /*
385 * Do not record the first disk stats as it reflects the aggregated disks stats since the
386 * system boot up and is not in sync with the polling period. This will lead to spurious
387 * I/O overuse alerting.
388 */
389 mLastSystemWideIoMonitorTime = time;
390 return {};
391 }
392 const auto diskStats = procDiskStatsCollector.promote()->deltaSystemWideDiskStats();
393 mSystemWideWrittenBytes.push_back(
394 {.pollDurationInSecs = difftime(time, mLastSystemWideIoMonitorTime),
395 .bytesInKib = diskStats.numKibWritten});
396 for (const auto& threshold : mIoOveruseConfigs->systemWideAlertThresholds()) {
397 int64_t accountedWrittenKib = 0;
398 double accountedDurationInSecs = 0;
399 size_t accountedPolls = 0;
400 for (auto rit = mSystemWideWrittenBytes.rbegin(); rit != mSystemWideWrittenBytes.rend();
401 ++rit) {
402 accountedWrittenKib += rit->bytesInKib;
403 accountedDurationInSecs += rit->pollDurationInSecs;
404 ++accountedPolls;
405 if (accountedDurationInSecs >= threshold.durationInSeconds) {
406 break;
407 }
408 }
409 // Heuristic to handle spurious alerting when the buffer is partially filled.
410 if (const size_t bufferSize = mSystemWideWrittenBytes.size();
411 accountedPolls == bufferSize && bufferSize < mPeriodicMonitorBufferSize + 1 &&
412 threshold.durationInSeconds > accountedDurationInSecs) {
413 continue;
414 }
415 const double thresholdKbps = threshold.writtenBytesPerSecond / 1024.0;
416 if (const auto kbps = accountedWrittenKib / accountedDurationInSecs;
417 kbps >= thresholdKbps) {
418 alertHandler();
419 break;
420 }
421 }
422 if (mSystemWideWrittenBytes.size() > mPeriodicMonitorBufferSize) {
423 mSystemWideWrittenBytes.erase(mSystemWideWrittenBytes.begin()); // Erase the oldest entry.
424 }
425 mLastSystemWideIoMonitorTime = time;
426 return {};
427 }
428
onDump(int fd) const429 Result<void> IoOveruseMonitor::onDump([[maybe_unused]] int fd) const {
430 // TODO(b/183436216): Dump the list of killed/disabled packages. Dump the list of packages that
431 // exceed xx% of their threshold.
432 return {};
433 }
434
dumpHelpText(int fd) const435 bool IoOveruseMonitor::dumpHelpText(int fd) const {
436 return WriteStringToFd(StringPrintf(kHelpText, name().c_str(), kResetResourceOveruseStatsFlag),
437 fd);
438 }
439
syncTodayIoUsageStatsLocked()440 void IoOveruseMonitor::syncTodayIoUsageStatsLocked() {
441 std::vector<UserPackageIoUsageStats> userPackageIoUsageStats;
442 if (const auto status = mWatchdogServiceHelper->getTodayIoUsageStats(&userPackageIoUsageStats);
443 !status.isOk()) {
444 ALOGE("Failed to fetch today I/O usage stats collected during previous boot: %s",
445 status.exceptionMessage().c_str());
446 return;
447 }
448 for (const auto& statsEntry : userPackageIoUsageStats) {
449 std::string uniqueId = uniquePackageIdStr(statsEntry.packageName,
450 static_cast<userid_t>(statsEntry.userId));
451 if (auto it = mUserPackageDailyIoUsageById.find(uniqueId);
452 it != mUserPackageDailyIoUsageById.end()) {
453 it->second += statsEntry.ioUsageStats;
454 continue;
455 }
456 mPrevBootIoUsageStatsById.insert(std::pair(uniqueId, statsEntry.ioUsageStats));
457 }
458 mDidReadTodayPrevBootStats = true;
459 }
460
notifyNativePackagesLocked(const std::unordered_map<uid_t,IoOveruseStats> & statsByUid)461 void IoOveruseMonitor::notifyNativePackagesLocked(
462 const std::unordered_map<uid_t, IoOveruseStats>& statsByUid) {
463 for (const auto& [uid, ioOveruseStats] : statsByUid) {
464 IResourceOveruseListener* listener;
465 if (const auto it = mOveruseListenersByUid.find(uid); it == mOveruseListenersByUid.end()) {
466 continue;
467 } else {
468 listener = it->second.get();
469 }
470 ResourceOveruseStats stats;
471 stats.set<ResourceOveruseStats::ioOveruseStats>(ioOveruseStats);
472 listener->onOveruse(stats);
473 }
474 if (DEBUG) {
475 ALOGD("Notified native packages on I/O overuse");
476 }
477 }
478
updateResourceOveruseConfigurations(const std::vector<ResourceOveruseConfiguration> & configs)479 Result<void> IoOveruseMonitor::updateResourceOveruseConfigurations(
480 const std::vector<ResourceOveruseConfiguration>& configs) {
481 std::unique_lock writeLock(mRwMutex);
482 if (!isInitializedLocked()) {
483 return Error(Status::EX_ILLEGAL_STATE) << name() << " is not initialized";
484 }
485 if (const auto result = mIoOveruseConfigs->update(configs); !result.ok()) {
486 return result;
487 }
488 std::thread writeToDiskThread([&]() {
489 if (set_sched_policy(0, SP_BACKGROUND) != 0) {
490 ALOGW("Failed to set background scheduling priority for writing resource overuse "
491 "configs to disk");
492 }
493 if (int result = pthread_setname_np(pthread_self(), "ResOveruseCfgWr"); result != 0) {
494 ALOGE("Failed to set thread name to 'ResOveruseCfgWr'");
495 }
496 std::unique_lock writeLock(mRwMutex);
497 if (const auto result = mIoOveruseConfigs->writeToDisk(); !result.ok()) {
498 ALOGE("Failed to write resource overuse configs to disk: %s",
499 result.error().message().c_str());
500 }
501 });
502 writeToDiskThread.detach();
503 return {};
504 }
505
getResourceOveruseConfigurations(std::vector<ResourceOveruseConfiguration> * configs) const506 Result<void> IoOveruseMonitor::getResourceOveruseConfigurations(
507 std::vector<ResourceOveruseConfiguration>* configs) const {
508 std::shared_lock readLock(mRwMutex);
509 if (!isInitializedLocked()) {
510 return Error(Status::EX_ILLEGAL_STATE) << name() << " is not initialized";
511 }
512 mIoOveruseConfigs->get(configs);
513 return {};
514 }
515
addIoOveruseListener(const sp<IResourceOveruseListener> & listener)516 Result<void> IoOveruseMonitor::addIoOveruseListener(const sp<IResourceOveruseListener>& listener) {
517 if (listener == nullptr) {
518 return Error(Status::EX_ILLEGAL_ARGUMENT) << "Must provide non-null listener";
519 }
520 pid_t callingPid = IPCThreadState::self()->getCallingPid();
521 uid_t callingUid = IPCThreadState::self()->getCallingUid();
522 auto binder = BnResourceOveruseListener::asBinder(listener);
523 sp<BinderDeathRecipient> binderDeathRecipient;
524 {
525 std::unique_lock writeLock(mRwMutex);
526 if (mBinderDeathRecipient == nullptr) {
527 return Error(Status::EX_ILLEGAL_STATE) << "Service is not initialized";
528 }
529 if (findListenerAndProcessLocked(binder, nullptr)) {
530 ALOGW("Failed to register the I/O overuse listener (pid: %d, uid: %d) as it is already "
531 "registered",
532 callingPid, callingUid);
533 return {};
534 }
535 mOveruseListenersByUid[callingUid] = listener;
536 binderDeathRecipient = mBinderDeathRecipient;
537 }
538 if (const auto status = binder->linkToDeath(binderDeathRecipient); status != OK) {
539 std::unique_lock writeLock(mRwMutex);
540 if (const auto& it = mOveruseListenersByUid.find(callingUid);
541 it != mOveruseListenersByUid.end() &&
542 BnResourceOveruseListener::asBinder(it->second) == binder) {
543 mOveruseListenersByUid.erase(it);
544 }
545 return Error(Status::EX_ILLEGAL_STATE)
546 << "(pid " << callingPid << ", uid: " << callingUid << ") is dead";
547 }
548 if (DEBUG) {
549 ALOGD("Added I/O overuse listener for uid: %d", callingUid);
550 }
551 return {};
552 }
553
removeIoOveruseListener(const sp<IResourceOveruseListener> & listener)554 Result<void> IoOveruseMonitor::removeIoOveruseListener(
555 const sp<IResourceOveruseListener>& listener) {
556 if (listener == nullptr) {
557 return Error(Status::EX_ILLEGAL_ARGUMENT) << "Must provide non-null listener";
558 }
559 std::unique_lock writeLock(mRwMutex);
560 if (mBinderDeathRecipient == nullptr) {
561 return Error(Status::EX_ILLEGAL_STATE) << "Service is not initialized";
562 }
563 const auto processor = [&](ListenersByUidMap& listeners, ListenersByUidMap::const_iterator it) {
564 auto binder = BnResourceOveruseListener::asBinder(it->second);
565 binder->unlinkToDeath(mBinderDeathRecipient);
566 listeners.erase(it);
567 };
568 if (const auto binder = BnResourceOveruseListener::asBinder(listener);
569 !findListenerAndProcessLocked(binder, processor)) {
570 return Error(Status::EX_ILLEGAL_ARGUMENT) << "Listener is not previously registered";
571 }
572 if (DEBUG) {
573 ALOGD("Removed I/O overuse listener for uid: %d", IPCThreadState::self()->getCallingUid());
574 }
575 return {};
576 }
577
getIoOveruseStats(IoOveruseStats * ioOveruseStats) const578 Result<void> IoOveruseMonitor::getIoOveruseStats(IoOveruseStats* ioOveruseStats) const {
579 if (!isInitialized()) {
580 return Error(Status::EX_ILLEGAL_STATE) << "I/O overuse monitor is not initialized";
581 }
582 uid_t callingUid = IPCThreadState::self()->getCallingUid();
583 const auto packageInfosByUid = mPackageInfoResolver->getPackageInfosForUids({callingUid});
584 const PackageInfo* packageInfo;
585 if (const auto it = packageInfosByUid.find(callingUid); it == packageInfosByUid.end()) {
586 return Error(Status::EX_ILLEGAL_ARGUMENT)
587 << "Package information not available for calling UID(" << callingUid << ")";
588 } else {
589 packageInfo = &it->second;
590 }
591 std::shared_lock readLock(mRwMutex);
592 const UserPackageIoUsage* dailyIoUsage;
593 if (const auto it = mUserPackageDailyIoUsageById.find(
594 uniquePackageIdStr(packageInfo->packageIdentifier));
595 it == mUserPackageDailyIoUsageById.end()) {
596 return Error(Status::EX_ILLEGAL_ARGUMENT)
597 << "Calling UID " << callingUid << " doesn't have I/O overuse stats";
598 } else {
599 dailyIoUsage = &it->second;
600 }
601 ioOveruseStats->killableOnOveruse = mIoOveruseConfigs->isSafeToKill(*packageInfo);
602 const auto thresholdBytes = mIoOveruseConfigs->fetchThreshold(*packageInfo);
603 ioOveruseStats->remainingWriteBytes =
604 diff(thresholdBytes,
605 diff(dailyIoUsage->writtenBytes, dailyIoUsage->forgivenWriteBytes));
606 ioOveruseStats->totalOveruses = dailyIoUsage->totalOveruses;
607 ioOveruseStats->writtenBytes = dailyIoUsage->writtenBytes;
608 const auto [startTime, durationInSeconds] =
609 calculateStartAndDuration(mLastUserPackageIoMonitorTime);
610 ioOveruseStats->startTime = startTime;
611 ioOveruseStats->durationInSeconds = durationInSeconds;
612 if (DEBUG) {
613 ALOGD("Returning I/O overuse stats for uid: %d", callingUid);
614 }
615 return {};
616 }
617
resetIoOveruseStats(const std::vector<std::string> & packageNames)618 Result<void> IoOveruseMonitor::resetIoOveruseStats(const std::vector<std::string>& packageNames) {
619 if (const auto status = mWatchdogServiceHelper->resetResourceOveruseStats(packageNames);
620 !status.isOk()) {
621 return Error() << "Failed to reset stats in watchdog service: " << status.toString8();
622 }
623 std::unordered_set<std::string> uniquePackageNames;
624 std::copy(packageNames.begin(), packageNames.end(),
625 std::inserter(uniquePackageNames, uniquePackageNames.end()));
626 std::unique_lock writeLock(mRwMutex);
627 for (auto& [key, usage] : mUserPackageDailyIoUsageById) {
628 if (uniquePackageNames.find(usage.packageInfo.packageIdentifier.name) !=
629 uniquePackageNames.end()) {
630 usage.resetStats();
631 }
632 }
633 return {};
634 }
635
removeStatsForUser(userid_t userId)636 void IoOveruseMonitor::removeStatsForUser(userid_t userId) {
637 std::unique_lock writeLock(mRwMutex);
638 for (auto it = mUserPackageDailyIoUsageById.begin();
639 it != mUserPackageDailyIoUsageById.end();) {
640 if (multiuser_get_user_id(it->second.packageInfo.packageIdentifier.uid) == userId) {
641 it = mUserPackageDailyIoUsageById.erase(it);
642 } else {
643 ++it;
644 }
645 }
646 // |mPrevBootIoUsageStatsById| keys are constructed using |uniquePackageIdStr| method. Thus, the
647 // key suffix would contain the userId. The value in this map is |IoUsageStats|, which doesn't
648 // contain the userId, so this is the only way to delete cached previous boot stats for
649 // the removed user.
650 std::string keySuffix = StringPrintf(":%" PRId32, userId);
651 for (auto it = mPrevBootIoUsageStatsById.begin(); it != mPrevBootIoUsageStatsById.end();) {
652 if (EndsWith(it->first, keySuffix)) {
653 it = mPrevBootIoUsageStatsById.erase(it);
654 } else {
655 ++it;
656 }
657 }
658 for (auto it = mLatestIoOveruseStats.begin(); it != mLatestIoOveruseStats.end();) {
659 if (multiuser_get_user_id(it->uid) == userId) {
660 it = mLatestIoOveruseStats.erase(it);
661 } else {
662 ++it;
663 }
664 }
665 }
666
handleBinderDeath(const wp<IBinder> & who)667 void IoOveruseMonitor::handleBinderDeath(const wp<IBinder>& who) {
668 std::unique_lock writeLock(mRwMutex);
669 findListenerAndProcessLocked(who.promote(),
670 [&](ListenersByUidMap& listeners,
671 ListenersByUidMap::const_iterator it) {
672 ALOGW("Resource overuse notification handler died for uid(%d)",
673 it->first);
674 listeners.erase(it);
675 });
676 }
677
findListenerAndProcessLocked(const sp<IBinder> & binder,const Processor & processor)678 bool IoOveruseMonitor::findListenerAndProcessLocked(const sp<IBinder>& binder,
679 const Processor& processor) {
680 for (auto it = mOveruseListenersByUid.begin(); it != mOveruseListenersByUid.end(); ++it) {
681 if (BnResourceOveruseListener::asBinder(it->second) != binder) {
682 continue;
683 }
684 if (processor != nullptr) {
685 processor(mOveruseListenersByUid, it);
686 }
687 return true;
688 }
689 return false;
690 }
691
UserPackageIoUsage(const PackageInfo & pkgInfo,const UidIoStats & uidIoStats,const bool isGarageModeActive)692 IoOveruseMonitor::UserPackageIoUsage::UserPackageIoUsage(const PackageInfo& pkgInfo,
693 const UidIoStats& uidIoStats,
694 const bool isGarageModeActive) {
695 packageInfo = pkgInfo;
696 if (isGarageModeActive) {
697 writtenBytes.garageModeBytes = uidIoStats.sumWriteBytes();
698 } else {
699 writtenBytes.foregroundBytes = uidIoStats.metrics[WRITE_BYTES][FOREGROUND];
700 writtenBytes.backgroundBytes = uidIoStats.metrics[WRITE_BYTES][BACKGROUND];
701 }
702 }
703
operator +=(const UserPackageIoUsage & r)704 IoOveruseMonitor::UserPackageIoUsage& IoOveruseMonitor::UserPackageIoUsage::operator+=(
705 const UserPackageIoUsage& r) {
706 if (id() == r.id()) {
707 packageInfo = r.packageInfo;
708 }
709 writtenBytes = sum(writtenBytes, r.writtenBytes);
710 return *this;
711 }
712
operator +=(const IoUsageStats & ioUsageStats)713 IoOveruseMonitor::UserPackageIoUsage& IoOveruseMonitor::UserPackageIoUsage::operator+=(
714 const IoUsageStats& ioUsageStats) {
715 writtenBytes = sum(writtenBytes, ioUsageStats.writtenBytes);
716 forgivenWriteBytes = sum(forgivenWriteBytes, ioUsageStats.forgivenWriteBytes);
717 totalOveruses += ioUsageStats.totalOveruses;
718 return *this;
719 }
720
id() const721 const std::string IoOveruseMonitor::UserPackageIoUsage::id() const {
722 return uniquePackageIdStr(packageInfo.packageIdentifier);
723 }
724
resetStats()725 void IoOveruseMonitor::UserPackageIoUsage::resetStats() {
726 writtenBytes = {};
727 forgivenWriteBytes = {};
728 totalOveruses = 0;
729 isPackageWarned = false;
730 lastSyncedWrittenBytes = 0;
731 }
732
733 } // namespace watchdog
734 } // namespace automotive
735 } // namespace android
736