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