• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&currentTm));
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(&currentTime, &currentGmt);
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