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