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