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