1 /*
2  * Copyright 2021 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 #include "IoOveruseMonitor.h"
18 #include "MockIoOveruseConfigs.h"
19 #include "MockPackageInfoResolver.h"
20 #include "MockProcDiskStats.h"
21 #include "MockResourceOveruseListener.h"
22 #include "MockUidStatsCollector.h"
23 #include "MockWatchdogServiceHelper.h"
24 #include "PackageInfoTestUtils.h"
25 
26 #include <binder/IPCThreadState.h>
27 #include <binder/Status.h>
28 #include <utils/RefBase.h>
29 
30 #include <functional>
31 #include <tuple>
32 #include <unordered_map>
33 
34 namespace android {
35 namespace automotive {
36 namespace watchdog {
37 
38 using ::android::IPCThreadState;
39 using ::android::RefBase;
40 using ::android::sp;
41 using ::android::automotive::watchdog::internal::IoOveruseAlertThreshold;
42 using ::android::automotive::watchdog::internal::PackageIdentifier;
43 using ::android::automotive::watchdog::internal::PackageInfo;
44 using ::android::automotive::watchdog::internal::PackageIoOveruseStats;
45 using ::android::automotive::watchdog::internal::ResourceOveruseConfiguration;
46 using ::android::automotive::watchdog::internal::UidType;
47 using ::android::automotive::watchdog::internal::UserPackageIoUsageStats;
48 using ::android::base::Error;
49 using ::android::base::Result;
50 using ::android::base::StringAppendF;
51 using ::android::binder::Status;
52 using ::testing::_;
53 using ::testing::DoAll;
54 using ::testing::Eq;
55 using ::testing::Return;
56 using ::testing::ReturnRef;
57 using ::testing::SaveArg;
58 using ::testing::SetArgPointee;
59 using ::testing::UnorderedElementsAreArray;
60 
61 namespace {
62 
63 constexpr size_t kTestMonitorBufferSize = 3;
64 constexpr int64_t KTestMinSyncWrittenBytes = 5'000;
65 constexpr double kTestIoOveruseWarnPercentage = 80;
66 constexpr std::chrono::seconds kTestMonitorInterval = 5s;
67 constexpr std::chrono::seconds kMaxWaitSeconds = 5s;
68 
toIoOveruseAlertThreshold(const int64_t durationInSeconds,const int64_t writtenBytesPerSecond)69 IoOveruseAlertThreshold toIoOveruseAlertThreshold(const int64_t durationInSeconds,
70                                                   const int64_t writtenBytesPerSecond) {
71     IoOveruseAlertThreshold threshold;
72     threshold.durationInSeconds = durationInSeconds;
73     threshold.writtenBytesPerSecond = writtenBytesPerSecond;
74     return threshold;
75 }
76 
77 struct PackageWrittenBytes {
78     PackageInfo packageInfo;
79     int32_t foregroundBytes;
80     int32_t backgroundBytes;
81 };
82 
constructPerStateBytes(const int64_t fgBytes,const int64_t bgBytes,const int64_t gmBytes)83 PerStateBytes constructPerStateBytes(const int64_t fgBytes, const int64_t bgBytes,
84                                      const int64_t gmBytes) {
85     PerStateBytes perStateBytes;
86     perStateBytes.foregroundBytes = fgBytes;
87     perStateBytes.backgroundBytes = bgBytes;
88     perStateBytes.garageModeBytes = gmBytes;
89     return perStateBytes;
90 }
91 
constructIoOveruseStats(const bool isKillable,const PerStateBytes & remaining,const PerStateBytes & written,const int totalOveruses,const int64_t startTime,const int64_t durationInSeconds)92 IoOveruseStats constructIoOveruseStats(const bool isKillable, const PerStateBytes& remaining,
93                                        const PerStateBytes& written, const int totalOveruses,
94                                        const int64_t startTime, const int64_t durationInSeconds) {
95     IoOveruseStats stats;
96     stats.killableOnOveruse = isKillable;
97     stats.remainingWriteBytes = remaining;
98     stats.startTime = startTime;
99     stats.durationInSeconds = durationInSeconds;
100     stats.writtenBytes = written;
101     stats.totalOveruses = totalOveruses;
102 
103     return stats;
104 }
105 
constructResourceOveruseStats(IoOveruseStats ioOveruseStats)106 ResourceOveruseStats constructResourceOveruseStats(IoOveruseStats ioOveruseStats) {
107     ResourceOveruseStats stats;
108     stats.set<ResourceOveruseStats::ioOveruseStats>(ioOveruseStats);
109     return stats;
110 }
111 
constructPackageIoOveruseStats(const int32_t uid,const bool shouldNotify,const bool isKillable,const PerStateBytes & remaining,const PerStateBytes & written,const PerStateBytes & forgiven,const int totalOveruses,const int64_t startTime,const int64_t durationInSeconds)112 PackageIoOveruseStats constructPackageIoOveruseStats(
113         const int32_t uid, const bool shouldNotify, const bool isKillable,
114         const PerStateBytes& remaining, const PerStateBytes& written, const PerStateBytes& forgiven,
115         const int totalOveruses, const int64_t startTime, const int64_t durationInSeconds) {
116     PackageIoOveruseStats stats;
117     stats.uid = uid;
118     stats.shouldNotify = shouldNotify;
119     stats.forgivenWriteBytes = forgiven;
120     stats.ioOveruseStats = constructIoOveruseStats(isKillable, remaining, written, totalOveruses,
121                                                    startTime, durationInSeconds);
122 
123     return stats;
124 }
125 
constructUserPackageIoUsageStats(userid_t userId,const std::string & packageName,const PerStateBytes & writtenBytes,const PerStateBytes & forgivenWriteBytes,int32_t totalOveruses)126 UserPackageIoUsageStats constructUserPackageIoUsageStats(userid_t userId,
127                                                          const std::string& packageName,
128                                                          const PerStateBytes& writtenBytes,
129                                                          const PerStateBytes& forgivenWriteBytes,
130                                                          int32_t totalOveruses) {
131     UserPackageIoUsageStats stats;
132     stats.userId = userId;
133     stats.packageName = packageName;
134     stats.ioUsageStats.writtenBytes = writtenBytes;
135     stats.ioUsageStats.forgivenWriteBytes = forgivenWriteBytes;
136     stats.ioUsageStats.totalOveruses = totalOveruses;
137     return stats;
138 }
139 
140 class ScopedChangeCallingUid : public RefBase {
141 public:
ScopedChangeCallingUid(uid_t uid)142     explicit ScopedChangeCallingUid(uid_t uid) {
143         mCallingUid = IPCThreadState::self()->getCallingUid();
144         mCallingPid = IPCThreadState::self()->getCallingPid();
145         if (mCallingUid == uid) {
146             return;
147         }
148         mChangedUid = uid;
149         int64_t token = ((int64_t)mChangedUid << 32) | mCallingPid;
150         IPCThreadState::self()->restoreCallingIdentity(token);
151     }
~ScopedChangeCallingUid()152     ~ScopedChangeCallingUid() {
153         if (mCallingUid == mChangedUid) {
154             return;
155         }
156         int64_t token = ((int64_t)mCallingUid << 32) | mCallingPid;
157         IPCThreadState::self()->restoreCallingIdentity(token);
158     }
159 
160 private:
161     uid_t mCallingUid;
162     uid_t mChangedUid;
163     pid_t mCallingPid;
164 };
165 
toString(const std::vector<PackageIoOveruseStats> & ioOveruseStats)166 std::string toString(const std::vector<PackageIoOveruseStats>& ioOveruseStats) {
167     if (ioOveruseStats.empty()) {
168         return "empty";
169     }
170     std::string buffer;
171     for (const auto& stats : ioOveruseStats) {
172         StringAppendF(&buffer, "%s\n", stats.toString().c_str());
173     }
174     return buffer;
175 }
176 
177 }  // namespace
178 
179 namespace internal {
180 
181 class IoOveruseMonitorPeer : public RefBase {
182 public:
IoOveruseMonitorPeer(const sp<IoOveruseMonitor> & ioOveruseMonitor)183     explicit IoOveruseMonitorPeer(const sp<IoOveruseMonitor>& ioOveruseMonitor) :
184           mIoOveruseMonitor(ioOveruseMonitor) {}
185 
init(const sp<IIoOveruseConfigs> & ioOveruseConfigs,const sp<IPackageInfoResolver> & packageInfoResolver)186     Result<void> init(const sp<IIoOveruseConfigs>& ioOveruseConfigs,
187                       const sp<IPackageInfoResolver>& packageInfoResolver) {
188         if (const auto result = mIoOveruseMonitor->init(); !result.ok()) {
189             return result;
190         }
191         mIoOveruseMonitor->mMinSyncWrittenBytes = KTestMinSyncWrittenBytes;
192         mIoOveruseMonitor->mPeriodicMonitorBufferSize = kTestMonitorBufferSize;
193         mIoOveruseMonitor->mIoOveruseWarnPercentage = kTestIoOveruseWarnPercentage;
194         mIoOveruseMonitor->mIoOveruseConfigs = ioOveruseConfigs;
195         mIoOveruseMonitor->mPackageInfoResolver = packageInfoResolver;
196         return {};
197     }
198 
199 private:
200     sp<IoOveruseMonitor> mIoOveruseMonitor;
201 };
202 
203 }  // namespace internal
204 
205 class IoOveruseMonitorTest : public ::testing::Test {
206 protected:
SetUp()207     virtual void SetUp() {
208         mMockWatchdogServiceHelper = sp<MockWatchdogServiceHelper>::make();
209         mMockIoOveruseConfigs = sp<MockIoOveruseConfigs>::make();
210         mMockPackageInfoResolver = sp<MockPackageInfoResolver>::make();
211         mMockUidStatsCollector = sp<MockUidStatsCollector>::make();
212         mIoOveruseMonitor = sp<IoOveruseMonitor>::make(mMockWatchdogServiceHelper);
213         mIoOveruseMonitorPeer = sp<internal::IoOveruseMonitorPeer>::make(mIoOveruseMonitor);
214         mIoOveruseMonitorPeer->init(mMockIoOveruseConfigs, mMockPackageInfoResolver);
215         setUpPackagesAndConfigurations();
216     }
217 
TearDown()218     virtual void TearDown() {
219         mMockWatchdogServiceHelper.clear();
220         mMockIoOveruseConfigs.clear();
221         mMockPackageInfoResolver.clear();
222         mMockUidStatsCollector.clear();
223         mIoOveruseMonitor.clear();
224         mIoOveruseMonitorPeer.clear();
225     }
226 
setUpPackagesAndConfigurations()227     void setUpPackagesAndConfigurations() {
228         ON_CALL(*mMockPackageInfoResolver, getPackageInfosForUids(_))
229                 .WillByDefault(Return(kPackageInfosByUid));
230         mMockIoOveruseConfigs->injectPackageConfigs({
231                 {"system.daemon",
232                  {constructPerStateBytes(/*fgBytes=*/80'000, /*bgBytes=*/40'000,
233                                          /*gmBytes=*/100'000),
234                   /*isSafeToKill=*/false}},
235                 {"com.android.google.package",
236                  {constructPerStateBytes(/*fgBytes=*/70'000, /*bgBytes=*/30'000,
237                                          /*gmBytes=*/100'000),
238                   /*isSafeToKill=*/true}},
239                 {"com.android.kitchensink",
240                  {constructPerStateBytes(/*fgBytes=*/30'000, /*bgBytes=*/15'000,
241                                          /*gmBytes=*/10'000),
242                   /*isSafeToKill=*/true}},
243         });
244     }
245 
constructUidStats(std::unordered_map<uid_t,std::tuple<int32_t,int32_t>> writtenBytesByUid)246     std::vector<UidStats> constructUidStats(
247             std::unordered_map<uid_t, std::tuple<int32_t, int32_t>> writtenBytesByUid) {
248         std::vector<UidStats> uidStats;
249         for (const auto& [uid, writtenBytes] : writtenBytesByUid) {
250             PackageInfo packageInfo;
251             if (kPackageInfosByUid.find(uid) != kPackageInfosByUid.end()) {
252                 packageInfo = kPackageInfosByUid.at(uid);
253             } else {
254                 packageInfo.packageIdentifier.uid = uid;
255             }
256             uidStats.push_back(UidStats{.packageInfo = packageInfo,
257                                         .ioStats = {/*fgRdBytes=*/989'000,
258                                                     /*bgRdBytes=*/678'000,
259                                                     /*fgWrBytes=*/std::get<0>(writtenBytes),
260                                                     /*bgWrBytes=*/std::get<1>(writtenBytes),
261                                                     /*fgFsync=*/10'000, /*bgFsync=*/50'000}});
262         }
263         return uidStats;
264     }
265 
executeAsUid(uid_t uid,std::function<void ()> func)266     void executeAsUid(uid_t uid, std::function<void()> func) {
267         sp<ScopedChangeCallingUid> scopedChangeCallingUid = sp<ScopedChangeCallingUid>::make(uid);
268         ASSERT_NO_FATAL_FAILURE(func());
269     }
270 
271     sp<MockWatchdogServiceHelper> mMockWatchdogServiceHelper;
272     sp<MockIoOveruseConfigs> mMockIoOveruseConfigs;
273     sp<MockPackageInfoResolver> mMockPackageInfoResolver;
274     sp<MockUidStatsCollector> mMockUidStatsCollector;
275     sp<IoOveruseMonitor> mIoOveruseMonitor;
276     sp<internal::IoOveruseMonitorPeer> mIoOveruseMonitorPeer;
277 
278     static const std::unordered_map<uid_t, PackageInfo> kPackageInfosByUid;
279 };
280 
281 const std::unordered_map<uid_t, PackageInfo> IoOveruseMonitorTest::kPackageInfosByUid =
282         {{1001000,
283           constructPackageInfo(
284                   /*packageName=*/"system.daemon",
285                   /*uid=*/1001000, UidType::NATIVE)},
286          {1112345,
287           constructPackageInfo(
288                   /*packageName=*/"com.android.google.package",
289                   /*uid=*/1112345, UidType::APPLICATION)},
290          {1113999,
291           constructPackageInfo(
292                   /*packageName=*/"com.android.google.package",
293                   /*uid=*/1113999, UidType::APPLICATION)},
294          {1212345,
295           constructPackageInfo(
296                   /*packageName=*/"com.android.google.package",
297                   /*uid=*/1212345, UidType::APPLICATION)},
298          {1245678,
299           constructPackageInfo(
300                   /*packageName=*/"com.android.kitchensink",
301                   /*uid=*/1245678, UidType::APPLICATION)},
302          {1312345,
303           constructPackageInfo(
304                   /*packageName=*/"com.android.google.package",
305                   /*uid=*/1312345, UidType::APPLICATION)}};
306 
TEST_F(IoOveruseMonitorTest,TestOnPeriodicCollection)307 TEST_F(IoOveruseMonitorTest, TestOnPeriodicCollection) {
308     sp<MockResourceOveruseListener> mockResourceOveruseListener =
309             sp<MockResourceOveruseListener>::make();
310     ASSERT_NO_FATAL_FAILURE(executeAsUid(1001000, [&]() {
311         ASSERT_RESULT_OK(mIoOveruseMonitor->addIoOveruseListener(mockResourceOveruseListener));
312     }));
313 
314     /*
315      * Package "system.daemon" (UID: 1001000) exceeds warn threshold percentage of 80% but no
316      * warning is issued as it is a native UID.
317      */
318     EXPECT_CALL(*mMockUidStatsCollector, deltaStats())
319             .WillOnce(Return(
320                     constructUidStats({{1001000, {/*fgWrBytes=*/70'000, /*bgWrBytes=*/20'000}},
321                                        {1112345, {/*fgWrBytes=*/35'000, /*bgWrBytes=*/15'000}},
322                                        {1212345, {/*fgWrBytes=*/70'000, /*bgWrBytes=*/20'000}}})));
323 
324     std::vector<PackageIoOveruseStats> actualIoOveruseStats;
325     EXPECT_CALL(*mMockWatchdogServiceHelper, latestIoOveruseStats(_))
326             .WillOnce(DoAll(SaveArg<0>(&actualIoOveruseStats), Return(Status::ok())));
327 
328     time_t currentTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
329     const auto [startTime, durationInSeconds] = calculateStartAndDuration(currentTime);
330 
331     ASSERT_RESULT_OK(mIoOveruseMonitor->onPeriodicCollection(currentTime, SystemState::NORMAL_MODE,
332                                                              mMockUidStatsCollector, nullptr));
333 
334     std::vector<PackageIoOveruseStats> expectedIoOveruseStats =
335             {constructPackageIoOveruseStats(/*uid=*/1001000, /*shouldNotify=*/false,
336                                             /*isKillable=*/false, /*remaining=*/
337                                             constructPerStateBytes(10'000, 20'000, 100'000),
338                                             /*written=*/constructPerStateBytes(70'000, 20'000, 0),
339                                             /*forgiven=*/constructPerStateBytes(0, 0, 0),
340                                             /*totalOveruses=*/0, startTime, durationInSeconds),
341              constructPackageIoOveruseStats(/*uid=*/1112345, /*shouldNotify=*/false,
342                                             /*isKillable=*/true, /*remaining=*/
343                                             constructPerStateBytes(35'000, 15'000, 100'000),
344                                             /*written=*/constructPerStateBytes(35'000, 15'000, 0),
345                                             /*forgiven=*/constructPerStateBytes(0, 0, 0),
346                                             /*totalOveruses=*/0, startTime, durationInSeconds),
347              // Exceeds threshold.
348              constructPackageIoOveruseStats(/*uid=*/1212345, /*shouldNotify=*/true,
349                                             /*isKillable=*/true,
350                                             /*remaining=*/
351                                             constructPerStateBytes(0, 10'000, 100'000),
352                                             /*written=*/constructPerStateBytes(70'000, 20'000, 0),
353                                             /*forgiven=*/constructPerStateBytes(70'000, 0, 0),
354                                             /*totalOveruses=*/1, startTime, durationInSeconds)};
355     EXPECT_THAT(actualIoOveruseStats, UnorderedElementsAreArray(expectedIoOveruseStats))
356             << "Expected: " << toString(expectedIoOveruseStats)
357             << "\nActual: " << toString(actualIoOveruseStats);
358 
359     ResourceOveruseStats actualOverusingNativeStats;
360     // Package "com.android.google.package" for user 11 changed uid from 1112345 to 1113999.
361     EXPECT_CALL(*mMockUidStatsCollector, deltaStats())
362             .WillOnce(Return(
363                     constructUidStats({{1001000, {/*fgWrBytes=*/30'000, /*bgWrBytes=*/0}},
364                                        {1113999, {/*fgWrBytes=*/25'000, /*bgWrBytes=*/10'000}},
365                                        {1212345, {/*fgWrBytes=*/20'000, /*bgWrBytes=*/30'000}}})));
366     actualIoOveruseStats.clear();
367     EXPECT_CALL(*mockResourceOveruseListener, onOveruse(_))
368             .WillOnce(DoAll(SaveArg<0>(&actualOverusingNativeStats), Return(Status::ok())));
369     EXPECT_CALL(*mMockWatchdogServiceHelper, latestIoOveruseStats(_))
370             .WillOnce(DoAll(SaveArg<0>(&actualIoOveruseStats), Return(Status::ok())));
371 
372     ASSERT_RESULT_OK(mIoOveruseMonitor->onPeriodicCollection(currentTime, SystemState::NORMAL_MODE,
373                                                              mMockUidStatsCollector, nullptr));
374 
375     const auto expectedOverusingNativeStats = constructResourceOveruseStats(
376             constructIoOveruseStats(/*isKillable=*/false,
377                                     /*remaining=*/constructPerStateBytes(0, 20'000, 100'000),
378                                     /*written=*/constructPerStateBytes(100'000, 20'000, 0),
379                                     /*totalOveruses=*/1, startTime, durationInSeconds));
380     EXPECT_THAT(actualOverusingNativeStats, Eq(expectedOverusingNativeStats))
381             << "Expected: " << expectedOverusingNativeStats.toString()
382             << "\nActual: " << actualOverusingNativeStats.toString();
383 
384     expectedIoOveruseStats =
385             {constructPackageIoOveruseStats(/*uid=*/1001000, /*shouldNotify=*/true,
386                                             /*isKillable=*/false, /*remaining=*/
387                                             constructPerStateBytes(0, 20'000, 100'000),
388                                             /*written=*/constructPerStateBytes(100'000, 20'000, 0),
389                                             /*forgiven=*/constructPerStateBytes(80'000, 0, 0),
390                                             /*totalOveruses=*/1, startTime, durationInSeconds),
391              // Exceeds warn threshold percentage.
392              constructPackageIoOveruseStats(/*uid=*/1113999, /*shouldNotify=*/true,
393                                             /*isKillable=*/true, /*remaining=*/
394                                             constructPerStateBytes(10'000, 5'000, 100'000),
395                                             /*written=*/constructPerStateBytes(60'000, 25'000, 0),
396                                             /*forgiven=*/constructPerStateBytes(0, 0, 0),
397                                             /*totalOveruses=*/0, startTime, durationInSeconds),
398              /*
399               * Exceeds threshold.
400               * The package was forgiven on previous overuse so the remaining bytes should only
401               * reflect the bytes written after the forgiven bytes.
402               */
403              constructPackageIoOveruseStats(/*uid=*/1212345, /*shouldNotify=*/true,
404                                             /*isKillable=*/true, /*remaining=*/
405                                             constructPerStateBytes(50'000, 0, 100'000),
406                                             /*written=*/constructPerStateBytes(90'000, 50'000, 0),
407                                             /*forgiven=*/constructPerStateBytes(70'000, 30'000, 0),
408                                             /*totalOveruses=*/2, startTime, durationInSeconds)};
409     EXPECT_THAT(actualIoOveruseStats, UnorderedElementsAreArray(expectedIoOveruseStats))
410             << "Expected: " << toString(expectedIoOveruseStats)
411             << "\nActual: " << toString(actualIoOveruseStats);
412 
413     /*
414      * Current date changed so the daily I/O usage stats should be reset and the latest I/O overuse
415      * stats should not aggregate with the previous day's stats.
416      */
417     EXPECT_CALL(*mMockUidStatsCollector, deltaStats())
418             .WillOnce(Return(
419                     constructUidStats({{1001000, {/*fgWrBytes=*/78'000, /*bgWrBytes=*/38'000}},
420                                        {1113999, {/*fgWrBytes=*/55'000, /*bgWrBytes=*/23'000}},
421                                        {1212345, {/*fgWrBytes=*/55'000, /*bgWrBytes=*/23'000}}})));
422     actualIoOveruseStats.clear();
423     EXPECT_CALL(*mMockWatchdogServiceHelper, latestIoOveruseStats(_))
424             .WillOnce(DoAll(SaveArg<0>(&actualIoOveruseStats), Return(Status::ok())));
425 
426     currentTime += (24 * 60 * 60);  // Change collection time to next day.
427     ASSERT_RESULT_OK(mIoOveruseMonitor->onPeriodicCollection(currentTime, SystemState::NORMAL_MODE,
428                                                              mMockUidStatsCollector, nullptr));
429 
430     const auto [nextDayStartTime, nextDayDuration] = calculateStartAndDuration(currentTime);
431     expectedIoOveruseStats =
432             {constructPackageIoOveruseStats(/*uid=*/1001000, /*shouldNotify=*/false,
433                                             /*isKillable=*/false, /*remaining=*/
434                                             constructPerStateBytes(2'000, 2'000, 100'000),
435                                             /*written=*/constructPerStateBytes(78'000, 38'000, 0),
436                                             /*forgiven=*/constructPerStateBytes(0, 0, 0),
437                                             /*totalOveruses=*/0, nextDayStartTime, nextDayDuration),
438              constructPackageIoOveruseStats(/*uid=*/1113999, /*shouldNotify=*/false,
439                                             /*isKillable=*/true, /*remaining=*/
440                                             constructPerStateBytes(15'000, 7'000, 100'000),
441                                             /*written=*/constructPerStateBytes(55'000, 23'000, 0),
442                                             /*forgiven=*/constructPerStateBytes(0, 0, 0),
443                                             /*totalOveruses=*/0, nextDayStartTime, nextDayDuration),
444              constructPackageIoOveruseStats(/*uid=*/1212345, /*shouldNotify=*/false,
445                                             /*isKillable=*/true, /*remaining=*/
446                                             constructPerStateBytes(15'000, 7'000, 100'000),
447                                             /*written=*/constructPerStateBytes(55'000, 23'000, 0),
448                                             /*forgiven=*/constructPerStateBytes(0, 0, 0),
449                                             /*totalOveruses=*/0, nextDayStartTime,
450                                             nextDayDuration)};
451 
452     EXPECT_THAT(actualIoOveruseStats, UnorderedElementsAreArray(expectedIoOveruseStats))
453             << "Expected: " << toString(expectedIoOveruseStats)
454             << "\nActual: " << toString(actualIoOveruseStats);
455 }
456 
TEST_F(IoOveruseMonitorTest,TestOnPeriodicCollectionWithGarageMode)457 TEST_F(IoOveruseMonitorTest, TestOnPeriodicCollectionWithGarageMode) {
458     sp<MockResourceOveruseListener> mockResourceOveruseListener =
459             sp<MockResourceOveruseListener>::make();
460     ASSERT_NO_FATAL_FAILURE(executeAsUid(1001000, [&]() {
461         ASSERT_RESULT_OK(mIoOveruseMonitor->addIoOveruseListener(mockResourceOveruseListener));
462     }));
463 
464     /*
465      * Package "system.daemon" (UID: 1001000) exceeds warn threshold percentage of 80% but no
466      * warning is issued as it is a native UID.
467      */
468     EXPECT_CALL(*mMockUidStatsCollector, deltaStats())
469             .WillOnce(Return(
470                     constructUidStats({{1001000, {/*fgWrBytes=*/70'000, /*bgWrBytes=*/60'000}},
471                                        {1112345, {/*fgWrBytes=*/35'000, /*bgWrBytes=*/15'000}},
472                                        {1212345, {/*fgWrBytes=*/90'000, /*bgWrBytes=*/20'000}}})));
473 
474     ResourceOveruseStats actualOverusingNativeStats;
475     EXPECT_CALL(*mockResourceOveruseListener, onOveruse(_))
476             .WillOnce(DoAll(SaveArg<0>(&actualOverusingNativeStats), Return(Status::ok())));
477     std::vector<PackageIoOveruseStats> actualIoOveruseStats;
478     EXPECT_CALL(*mMockWatchdogServiceHelper, latestIoOveruseStats(_))
479             .WillOnce(DoAll(SaveArg<0>(&actualIoOveruseStats), Return(Status::ok())));
480 
481     time_t currentTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
482     const auto [startTime, durationInSeconds] = calculateStartAndDuration(currentTime);
483 
484     ASSERT_RESULT_OK(mIoOveruseMonitor->onPeriodicCollection(currentTime, SystemState::GARAGE_MODE,
485                                                              mMockUidStatsCollector, nullptr));
486 
487     const auto expectedOverusingNativeStats = constructResourceOveruseStats(
488             constructIoOveruseStats(/*isKillable=*/false,
489                                     /*remaining=*/constructPerStateBytes(80'000, 40'000, 0),
490                                     /*written=*/constructPerStateBytes(0, 0, 130'000),
491                                     /*totalOveruses=*/1, startTime, durationInSeconds));
492     EXPECT_THAT(actualOverusingNativeStats, Eq(expectedOverusingNativeStats))
493             << "Expected: " << expectedOverusingNativeStats.toString()
494             << "\nActual: " << actualOverusingNativeStats.toString();
495 
496     const std::vector<PackageIoOveruseStats> expectedIoOveruseStats =
497             {constructPackageIoOveruseStats(/*uid=*/1001000, /*shouldNotify=*/true,
498                                             /*isKillable=*/false, /*remaining=*/
499                                             constructPerStateBytes(80'000, 40'000, 0),
500                                             /*written=*/constructPerStateBytes(0, 0, 130'000),
501                                             /*forgiven=*/constructPerStateBytes(0, 0, 100'000),
502                                             /*totalOveruses=*/1, startTime, durationInSeconds),
503              constructPackageIoOveruseStats(/*uid=*/1112345, /*shouldNotify=*/false,
504                                             /*isKillable=*/true, /*remaining=*/
505                                             constructPerStateBytes(70'000, 30'000, 50'000),
506                                             /*written=*/constructPerStateBytes(0, 0, 50'000),
507                                             /*forgiven=*/constructPerStateBytes(0, 0, 0),
508                                             /*totalOveruses=*/0, startTime, durationInSeconds),
509              // Exceeds threshold.
510              constructPackageIoOveruseStats(/*uid=*/1212345, /*shouldNotify=*/true,
511                                             /*isKillable=*/true,
512                                             /*remaining=*/
513                                             constructPerStateBytes(70'000, 30'000, 0),
514                                             /*written=*/constructPerStateBytes(0, 0, 110'000),
515                                             /*forgiven=*/constructPerStateBytes(0, 0, 100'000),
516                                             /*totalOveruses=*/1, startTime, durationInSeconds)};
517     EXPECT_THAT(actualIoOveruseStats, UnorderedElementsAreArray(expectedIoOveruseStats))
518             << "Expected: " << toString(expectedIoOveruseStats)
519             << "\nActual: " << toString(actualIoOveruseStats);
520 }
521 
TEST_F(IoOveruseMonitorTest,TestOnPeriodicCollectionWithZeroWriteBytes)522 TEST_F(IoOveruseMonitorTest, TestOnPeriodicCollectionWithZeroWriteBytes) {
523     EXPECT_CALL(*mMockUidStatsCollector, deltaStats())
524             .WillOnce(Return(constructUidStats({{1001000, {/*fgWrBytes=*/0, /*bgWrBytes=*/0}},
525                                                 {1112345, {/*fgWrBytes=*/0, /*bgWrBytes=*/0}},
526                                                 {1212345, {/*fgWrBytes=*/0, /*bgWrBytes=*/0}}})));
527 
528     EXPECT_CALL(*mMockPackageInfoResolver, getPackageInfosForUids(_)).Times(0);
529     EXPECT_CALL(*mMockIoOveruseConfigs, fetchThreshold(_)).Times(0);
530     EXPECT_CALL(*mMockIoOveruseConfigs, isSafeToKill(_)).Times(0);
531     EXPECT_CALL(*mMockWatchdogServiceHelper, latestIoOveruseStats(_)).Times(0);
532 
533     ASSERT_RESULT_OK(
534             mIoOveruseMonitor->onPeriodicCollection(std::chrono::system_clock::to_time_t(
535                                                             std::chrono::system_clock::now()),
536                                                     SystemState::NORMAL_MODE,
537                                                     mMockUidStatsCollector, nullptr));
538 }
539 
TEST_F(IoOveruseMonitorTest,TestOnPeriodicCollectionWithExtremeOveruse)540 TEST_F(IoOveruseMonitorTest, TestOnPeriodicCollectionWithExtremeOveruse) {
541     EXPECT_CALL(*mMockUidStatsCollector, deltaStats())
542             .WillOnce(Return(
543                     constructUidStats({{1001000, {/*fgWrBytes=*/190'000, /*bgWrBytes=*/42'000}},
544                                        {1212345, {/*fgWrBytes=*/90'000, /*bgWrBytes=*/90'000}}})));
545 
546     time_t currentTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
547     const auto [startTime, durationInSeconds] = calculateStartAndDuration(currentTime);
548 
549     std::vector<PackageIoOveruseStats> actualPackageIoOveruseStats;
550     EXPECT_CALL(*mMockWatchdogServiceHelper, latestIoOveruseStats(_))
551             .WillOnce(DoAll(SaveArg<0>(&actualPackageIoOveruseStats), Return(Status::ok())));
552 
553     ASSERT_RESULT_OK(mIoOveruseMonitor->onPeriodicCollection(currentTime, SystemState::NORMAL_MODE,
554                                                              mMockUidStatsCollector, nullptr));
555 
556     std::vector<PackageIoOveruseStats> expectedPackageIoOveruseStats =
557             {constructPackageIoOveruseStats(/*uid=*/1001000, /*shouldNotify=*/true,
558                                             /*isKillable=*/false, /*remaining=*/
559                                             constructPerStateBytes(0, 0, 100'000),
560                                             /*written=*/constructPerStateBytes(190'000, 42'000, 0),
561                                             /*forgiven=*/constructPerStateBytes(160'000, 40'000, 0),
562                                             /*totalOveruses=*/3, startTime, durationInSeconds),
563              constructPackageIoOveruseStats(/*uid=*/1212345, /*shouldNotify=*/true,
564                                             /*isKillable=*/true, /*remaining=*/
565                                             constructPerStateBytes(0, 0, 100'000),
566                                             /*written=*/constructPerStateBytes(90'000, 90'000, 0),
567                                             /*forgiven=*/constructPerStateBytes(70'000, 90'000, 0),
568                                             /*totalOveruses=*/4, startTime, durationInSeconds)};
569     EXPECT_THAT(actualPackageIoOveruseStats,
570                 UnorderedElementsAreArray(expectedPackageIoOveruseStats))
571             << "Expected: " << toString(expectedPackageIoOveruseStats)
572             << "\nActual: " << toString(actualPackageIoOveruseStats);
573 }
574 
TEST_F(IoOveruseMonitorTest,TestOnPeriodicCollectionWithExtremeOveruseInGarageMode)575 TEST_F(IoOveruseMonitorTest, TestOnPeriodicCollectionWithExtremeOveruseInGarageMode) {
576     EXPECT_CALL(*mMockUidStatsCollector, deltaStats())
577             .WillOnce(Return(
578                     constructUidStats({{1001000, {/*fgWrBytes=*/190'000, /*bgWrBytes=*/42'000}},
579                                        {1212345, {/*fgWrBytes=*/90'000, /*bgWrBytes=*/90'000}}})));
580 
581     time_t currentTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
582     const auto [startTime, durationInSeconds] = calculateStartAndDuration(currentTime);
583 
584     std::vector<PackageIoOveruseStats> actualPackageIoOveruseStats;
585     EXPECT_CALL(*mMockWatchdogServiceHelper, latestIoOveruseStats(_))
586             .WillOnce(DoAll(SaveArg<0>(&actualPackageIoOveruseStats), Return(Status::ok())));
587 
588     ASSERT_RESULT_OK(mIoOveruseMonitor->onPeriodicCollection(currentTime, SystemState::GARAGE_MODE,
589                                                              mMockUidStatsCollector, nullptr));
590 
591     std::vector<PackageIoOveruseStats> expectedPackageIoOveruseStats =
592             {constructPackageIoOveruseStats(/*uid=*/1001000, /*shouldNotify=*/true,
593                                             /*isKillable=*/false, /*remaining=*/
594                                             constructPerStateBytes(80'000, 40'000, 0),
595                                             /*written=*/constructPerStateBytes(0, 0, 232'000),
596                                             /*forgiven=*/constructPerStateBytes(0, 0, 200'000),
597                                             /*totalOveruses=*/2, startTime, durationInSeconds),
598              constructPackageIoOveruseStats(/*uid=*/1212345, /*shouldNotify=*/true,
599                                             /*isKillable=*/true, /*remaining=*/
600                                             constructPerStateBytes(70'000, 30'000, 0),
601                                             /*written=*/constructPerStateBytes(0, 0, 180'000),
602                                             /*forgiven=*/constructPerStateBytes(0, 0, 100'000),
603                                             /*totalOveruses=*/1, startTime, durationInSeconds)};
604     EXPECT_THAT(actualPackageIoOveruseStats,
605                 UnorderedElementsAreArray(expectedPackageIoOveruseStats))
606             << "Expected: " << toString(expectedPackageIoOveruseStats)
607             << "\nActual: " << toString(actualPackageIoOveruseStats);
608 }
609 
TEST_F(IoOveruseMonitorTest,TestOnPeriodicCollectionWithSmallWrittenBytes)610 TEST_F(IoOveruseMonitorTest, TestOnPeriodicCollectionWithSmallWrittenBytes) {
611     /*
612      * UID 1212345 current written bytes < |KTestMinSyncWrittenBytes| so the UID's stats are not
613      * synced.
614      */
615     EXPECT_CALL(*mMockUidStatsCollector, deltaStats())
616             .WillOnce(Return(
617                     constructUidStats({{1001000, {/*fgWrBytes=*/59'200, /*bgWrBytes=*/0}},
618                                        {1112345, {/*fgWrBytes=*/0, /*bgWrBytes=*/25'200}},
619                                        {1212345, {/*fgWrBytes=*/300, /*bgWrBytes=*/600}},
620                                        {1312345, {/*fgWrBytes=*/51'200, /*bgWrBytes=*/0}}})));
621 
622     std::vector<PackageIoOveruseStats> actualIoOveruseStats;
623     EXPECT_CALL(*mMockWatchdogServiceHelper, latestIoOveruseStats(_))
624             .WillOnce(DoAll(SaveArg<0>(&actualIoOveruseStats), Return(Status::ok())));
625 
626     time_t currentTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
627     const auto [startTime, durationInSeconds] = calculateStartAndDuration(currentTime);
628 
629     ASSERT_RESULT_OK(mIoOveruseMonitor->onPeriodicCollection(currentTime, SystemState::NORMAL_MODE,
630                                                              mMockUidStatsCollector, nullptr));
631 
632     std::vector<PackageIoOveruseStats> expectedIoOveruseStats =
633             {constructPackageIoOveruseStats(/*uid=*/1001000, /*shouldNotify=*/false,
634                                             /*isKillable=*/false, /*remaining=*/
635                                             constructPerStateBytes(20'800, 40'000, 100'000),
636                                             /*written=*/
637                                             constructPerStateBytes(59'200, 0, 0),
638                                             /*forgiven=*/constructPerStateBytes(0, 0, 0),
639                                             /*totalOveruses=*/0, startTime, durationInSeconds),
640              constructPackageIoOveruseStats(/*uid=*/1112345, /*shouldNotify=*/true,
641                                             /*isKillable=*/true, /*remaining=*/
642                                             constructPerStateBytes(70'000, 4'800, 100'000),
643                                             /*written=*/constructPerStateBytes(0, 25'200, 0),
644                                             /*forgiven=*/constructPerStateBytes(0, 0, 0),
645                                             /*totalOveruses=*/0, startTime, durationInSeconds),
646              constructPackageIoOveruseStats(/*uid=*/1312345, /*shouldNotify=*/false,
647                                             /*isKillable=*/true, /*remaining=*/
648                                             constructPerStateBytes(18'800, 30'000, 100'000),
649                                             /*written=*/constructPerStateBytes(51'200, 0, 0),
650                                             /*forgiven=*/constructPerStateBytes(0, 0, 0),
651                                             /*totalOveruses=*/0, startTime, durationInSeconds)};
652 
653     EXPECT_THAT(actualIoOveruseStats, UnorderedElementsAreArray(expectedIoOveruseStats))
654             << "Expected: " << toString(expectedIoOveruseStats)
655             << "\nActual: " << toString(actualIoOveruseStats);
656 
657     actualIoOveruseStats.clear();
658     EXPECT_CALL(*mMockWatchdogServiceHelper, latestIoOveruseStats(_))
659             .WillOnce(DoAll(SaveArg<0>(&actualIoOveruseStats), Return(Status::ok())));
660 
661     /*
662      * UID 1001000 current written bytes is < |kTestMinSyncWrittenBytes| but exceeds warn threshold
663      * but not killable so the UID's stats are not synced.
664      * UID 1112345 current written bytes is < |kTestMinSyncWrittenBytes| but exceeds threshold so
665      * the UID's stats are synced.
666      * UID 1212345 current written bytes is < |kTestMinSyncWrittenBytes| but total written bytes
667      * since last synced > |kTestMinSyncWrittenBytes| so the UID's stats are synced.
668      * UID 1312345 current written bytes is < |kTestMinSyncWrittenBytes| but exceeds warn threshold
669      * and killable so the UID's stat are synced.
670      */
671     EXPECT_CALL(*mMockUidStatsCollector, deltaStats())
672             .WillOnce(Return(constructUidStats(
673                     {{1001000, {/*fgWrBytes=*/KTestMinSyncWrittenBytes - 100, /*bgWrBytes=*/0}},
674                      {1112345, {/*fgWrBytes=*/0, /*bgWrBytes=*/KTestMinSyncWrittenBytes - 100}},
675                      {1212345, {/*fgWrBytes=*/KTestMinSyncWrittenBytes - 300, /*bgWrBytes=*/0}},
676                      {1312345, {/*fgWrBytes=*/KTestMinSyncWrittenBytes - 100, /*bgWrBytes=*/0}}})));
677 
678     ASSERT_RESULT_OK(mIoOveruseMonitor->onPeriodicCollection(currentTime, SystemState::NORMAL_MODE,
679                                                              mMockUidStatsCollector, nullptr));
680 
681     expectedIoOveruseStats =
682             {constructPackageIoOveruseStats(/*uid=*/1112345, /*shouldNotify=*/true,
683                                             /*isKillable=*/true, /*remaining=*/
684                                             constructPerStateBytes(70'000, 0, 100'000),
685                                             /*written=*/constructPerStateBytes(0, 30'100, 0),
686                                             /*forgiven=*/
687                                             constructPerStateBytes(0, 30'000, 0),
688                                             /*totalOveruses=*/1, startTime, durationInSeconds),
689              constructPackageIoOveruseStats(/*uid=*/1212345, /*shouldNotify=*/false,
690                                             /*isKillable=*/true, /*remaining=*/
691                                             constructPerStateBytes(65'000, 29'400, 100'000),
692                                             /*written=*/constructPerStateBytes(5'000, 600, 0),
693                                             /*forgiven=*/constructPerStateBytes(0, 0, 0),
694                                             /*totalOveruses=*/0, startTime, durationInSeconds),
695              constructPackageIoOveruseStats(/*uid=*/1312345, /*shouldNotify=*/true,
696                                             /*isKillable=*/true, /*remaining=*/
697                                             constructPerStateBytes(13'900, 30'000, 100'000),
698                                             /*written=*/constructPerStateBytes(56'100, 0, 0),
699                                             /*forgiven=*/constructPerStateBytes(0, 0, 0),
700                                             /*totalOveruses=*/0, startTime, durationInSeconds)};
701     EXPECT_THAT(actualIoOveruseStats, UnorderedElementsAreArray(expectedIoOveruseStats))
702             << "Expected: " << toString(expectedIoOveruseStats)
703             << "\nActual: " << toString(actualIoOveruseStats);
704 }
705 
TEST_F(IoOveruseMonitorTest,TestOnPeriodicCollectionWithNoPackageInfo)706 TEST_F(IoOveruseMonitorTest, TestOnPeriodicCollectionWithNoPackageInfo) {
707     EXPECT_CALL(*mMockUidStatsCollector, deltaStats())
708             .WillOnce(Return(
709                     constructUidStats({{2301000, {/*fgWrBytes=*/70'000, /*bgWrBytes=*/20'000}},
710                                        {2412345, {/*fgWrBytes=*/35'000, /*bgWrBytes=*/15'000}},
711                                        {2512345, {/*fgWrBytes=*/70'000, /*bgWrBytes=*/20'000}}})));
712 
713     EXPECT_CALL(*mMockIoOveruseConfigs, fetchThreshold(_)).Times(0);
714     EXPECT_CALL(*mMockIoOveruseConfigs, isSafeToKill(_)).Times(0);
715     EXPECT_CALL(*mMockWatchdogServiceHelper, latestIoOveruseStats(_)).Times(0);
716 
717     ASSERT_RESULT_OK(
718             mIoOveruseMonitor->onPeriodicCollection(std::chrono::system_clock::to_time_t(
719                                                             std::chrono::system_clock::now()),
720                                                     SystemState::NORMAL_MODE,
721                                                     mMockUidStatsCollector, nullptr));
722 }
723 
TEST_F(IoOveruseMonitorTest,TestOnPeriodicCollectionWithPrevBootStats)724 TEST_F(IoOveruseMonitorTest, TestOnPeriodicCollectionWithPrevBootStats) {
725     std::vector<UserPackageIoUsageStats> todayIoUsageStats =
726             {constructUserPackageIoUsageStats(
727                      /*userId=*/11, "com.android.google.package",
728                      /*writtenBytes=*/constructPerStateBytes(100'000, 85'000, 120'000),
729                      /*forgivenWriteBytes=*/constructPerStateBytes(70'000, 60'000, 100'000),
730                      /*totalOveruses=*/3),
731              constructUserPackageIoUsageStats(
732                      /*userId=*/12, "com.android.kitchensink",
733                      /*writtenBytes=*/constructPerStateBytes(50'000, 40'000, 35'000),
734                      /*forgivenWriteBytes=*/constructPerStateBytes(30'000, 30'000, 30'000),
735                      /*totalOveruses=*/6)};
736     EXPECT_CALL(*mMockWatchdogServiceHelper, getTodayIoUsageStats(_))
737             .WillOnce(DoAll(SetArgPointee<0>(todayIoUsageStats), Return(Status::ok())));
738 
739     EXPECT_CALL(*mMockUidStatsCollector, deltaStats())
740             .WillOnce(Return(
741                     constructUidStats({{1001000, {/*fgWrBytes=*/70'000, /*bgWrBytes=*/20'000}},
742                                        {1112345, {/*fgWrBytes=*/35'000, /*bgWrBytes=*/15'000}}})));
743 
744     std::vector<PackageIoOveruseStats> actualIoOveruseStats;
745     EXPECT_CALL(*mMockWatchdogServiceHelper, latestIoOveruseStats(_))
746             .WillOnce(DoAll(SaveArg<0>(&actualIoOveruseStats), Return(Status::ok())));
747 
748     time_t currentTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
749     const auto [startTime, durationInSeconds] = calculateStartAndDuration(currentTime);
750 
751     ASSERT_RESULT_OK(mIoOveruseMonitor->onPeriodicCollection(currentTime, SystemState::NORMAL_MODE,
752                                                              mMockUidStatsCollector, nullptr));
753 
754     std::vector<PackageIoOveruseStats> expectedIoOveruseStats =
755             {constructPackageIoOveruseStats(
756                      /*uid*=*/1001000, /*shouldNotify=*/false, /*isKillable=*/false,
757                      /*remaining=*/constructPerStateBytes(10'000, 20'000, 100'000),
758                      /*written=*/constructPerStateBytes(70'000, 20'000, 0),
759                      /*forgiven=*/constructPerStateBytes(0, 0, 0),
760                      /*totalOveruses=*/0, startTime, durationInSeconds),
761              constructPackageIoOveruseStats(
762                      /*uid*=*/1112345, /*shouldNotify=*/true, /*isKillable=*/true,
763                      /*remaining=*/constructPerStateBytes(5'000, 0, 80'000),
764                      /*written=*/constructPerStateBytes(135'000, 100'000, 120'000),
765                      /*forgiven=*/constructPerStateBytes(70'000, 90'000, 100'000),
766                      /*totalOveruses=*/4, startTime, durationInSeconds)};
767     EXPECT_THAT(actualIoOveruseStats, UnorderedElementsAreArray(expectedIoOveruseStats))
768             << "Expected: " << toString(expectedIoOveruseStats)
769             << "\nActual: " << toString(actualIoOveruseStats);
770 
771     EXPECT_CALL(*mMockUidStatsCollector, deltaStats())
772             .WillOnce(Return(
773                     constructUidStats({{1112345, {/*fgWrBytes=*/70'000, /*bgWrBytes=*/40'000}},
774                                        {1245678, {/*fgWrBytes=*/30'000, /*bgWrBytes=*/10'000}}})));
775 
776     actualIoOveruseStats.clear();
777     EXPECT_CALL(*mMockWatchdogServiceHelper, latestIoOveruseStats(_))
778             .WillOnce(DoAll(SaveArg<0>(&actualIoOveruseStats), Return(Status::ok())));
779 
780     ASSERT_RESULT_OK(mIoOveruseMonitor->onPeriodicCollection(currentTime, SystemState::GARAGE_MODE,
781                                                              mMockUidStatsCollector, nullptr));
782 
783     expectedIoOveruseStats = {constructPackageIoOveruseStats(
784                                       /*uid*=*/1112345, /*shouldNotify=*/true, /*isKillable=*/true,
785                                       /*remaining=*/constructPerStateBytes(5'000, 20'000, 0),
786                                       /*written=*/constructPerStateBytes(135'000, 100'000, 230'000),
787                                       /*forgiven=*/constructPerStateBytes(70'000, 90'000, 200'000),
788                                       /*totalOveruses=*/5, startTime, durationInSeconds),
789                               constructPackageIoOveruseStats(
790                                       /*uid*=*/1245678, /*shouldNotify=*/true, /*isKillable=*/true,
791                                       /*remaining=*/constructPerStateBytes(10'000, 5'000, 0),
792                                       /*written=*/constructPerStateBytes(50'000, 40'000, 75'000),
793                                       /*forgiven=*/constructPerStateBytes(30'000, 30'000, 70'000),
794                                       /*totalOveruses=*/10, startTime, durationInSeconds)};
795     EXPECT_THAT(actualIoOveruseStats, UnorderedElementsAreArray(expectedIoOveruseStats))
796             << "Expected: " << toString(expectedIoOveruseStats)
797             << "\nActual: " << toString(actualIoOveruseStats);
798 }
799 
TEST_F(IoOveruseMonitorTest,TestOnPeriodicCollectionWithErrorFetchingPrevBootStats)800 TEST_F(IoOveruseMonitorTest, TestOnPeriodicCollectionWithErrorFetchingPrevBootStats) {
801     EXPECT_CALL(*mMockWatchdogServiceHelper, getTodayIoUsageStats(_))
802             .WillOnce(Return(Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, "Illegal state")));
803 
804     EXPECT_CALL(*mMockUidStatsCollector, deltaStats())
805             .WillOnce(Return(
806                     constructUidStats({{1112345, {/*fgWrBytes=*/15'000, /*bgWrBytes=*/15'000}}})));
807 
808     time_t currentTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
809     const auto [startTime, durationInSeconds] = calculateStartAndDuration(currentTime);
810 
811     ASSERT_RESULT_OK(mIoOveruseMonitor->onPeriodicCollection(currentTime, SystemState::NORMAL_MODE,
812                                                              mMockUidStatsCollector, nullptr));
813 
814     std::vector<UserPackageIoUsageStats> todayIoUsageStats = {constructUserPackageIoUsageStats(
815             /*userId=*/11, "com.android.google.package",
816             /*writtenBytes=*/constructPerStateBytes(100'000, 85'000, 120'000),
817             /*forgivenWriteBytes=*/constructPerStateBytes(70'000, 60'000, 100'000),
818             /*totalOveruses=*/3)};
819     EXPECT_CALL(*mMockWatchdogServiceHelper, getTodayIoUsageStats(_))
820             .WillOnce(DoAll(SetArgPointee<0>(todayIoUsageStats), Return(Status::ok())));
821 
822     std::vector<PackageIoOveruseStats> actualIoOveruseStats;
823     EXPECT_CALL(*mMockWatchdogServiceHelper, latestIoOveruseStats(_))
824             .WillOnce(DoAll(SaveArg<0>(&actualIoOveruseStats), Return(Status::ok())));
825 
826     EXPECT_CALL(*mMockUidStatsCollector, deltaStats())
827             .WillOnce(Return(
828                     constructUidStats({{1112345, {/*fgWrBytes=*/20'000, /*bgWrBytes=*/40'000}}})));
829 
830     ASSERT_RESULT_OK(mIoOveruseMonitor->onPeriodicCollection(currentTime, SystemState::NORMAL_MODE,
831                                                              mMockUidStatsCollector, nullptr));
832 
833     std::vector<PackageIoOveruseStats> expectedIoOveruseStats = {constructPackageIoOveruseStats(
834             /*uid*=*/1112345, /*shouldNotify=*/true, /*isKillable=*/true,
835             /*remaining=*/constructPerStateBytes(5'000, 0, 80'000),
836             /*written=*/constructPerStateBytes(135'000, 140'000, 120'000),
837             /*forgiven=*/constructPerStateBytes(70'000, 120'000, 100'000),
838             /*totalOveruses=*/5, startTime, durationInSeconds)};
839     EXPECT_THAT(actualIoOveruseStats, UnorderedElementsAreArray(expectedIoOveruseStats))
840             << "Expected: " << toString(expectedIoOveruseStats)
841             << "\nActual: " << toString(actualIoOveruseStats);
842 }
843 
TEST_F(IoOveruseMonitorTest,TestOnPeriodicMonitor)844 TEST_F(IoOveruseMonitorTest, TestOnPeriodicMonitor) {
845     IIoOveruseConfigs::IoOveruseAlertThresholdSet alertThresholds =
846             {toIoOveruseAlertThreshold(
847                      /*durationInSeconds=*/10, /*writtenBytesPerSecond=*/15'360),
848              toIoOveruseAlertThreshold(
849                      /*durationInSeconds=*/17, /*writtenBytesPerSecond=*/10'240),
850              toIoOveruseAlertThreshold(
851                      /*durationInSeconds=*/23, /*writtenBytesPerSecond=*/7'168)};
852     ON_CALL(*mMockIoOveruseConfigs, systemWideAlertThresholds())
853             .WillByDefault(ReturnRef(alertThresholds));
854 
855     time_t time = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
856     const auto nextCollectionTime = [&]() -> time_t {
857         time += kTestMonitorInterval.count();
858         return time;
859     };
860     bool isAlertReceived = false;
861     const auto alertHandler = [&]() { isAlertReceived = true; };
862 
863     // 1st polling is ignored
864     sp<MockProcDiskStats> mockProcDiskStats = sp<MockProcDiskStats>::make();
865     EXPECT_CALL(*mockProcDiskStats, deltaSystemWideDiskStats()).Times(0);
866 
867     ASSERT_RESULT_OK(mIoOveruseMonitor->onPeriodicMonitor(nextCollectionTime(), mockProcDiskStats,
868                                                           alertHandler));
869     EXPECT_FALSE(isAlertReceived) << "Triggered spurious alert because first polling is ignored";
870 
871     // 2nd polling - guarded by the heuristic to handle spurious alerting on partially filled buffer
872     EXPECT_CALL(*mockProcDiskStats, deltaSystemWideDiskStats()).WillOnce([]() -> DiskStats {
873         return DiskStats{.numKibWritten = 70};
874     });
875 
876     ASSERT_RESULT_OK(mIoOveruseMonitor->onPeriodicMonitor(nextCollectionTime(), mockProcDiskStats,
877                                                           alertHandler));
878     EXPECT_FALSE(isAlertReceived) << "Triggered spurious alert when not exceeding the threshold";
879 
880     // 3rd polling exceeds first threshold
881     EXPECT_CALL(*mockProcDiskStats, deltaSystemWideDiskStats()).WillOnce([]() -> DiskStats {
882         return DiskStats{.numKibWritten = 90};
883     });
884 
885     ASSERT_RESULT_OK(mIoOveruseMonitor->onPeriodicMonitor(nextCollectionTime(), mockProcDiskStats,
886                                                           alertHandler));
887     EXPECT_TRUE(isAlertReceived) << "Failed to trigger alert when exceeding the threshold";
888 
889     isAlertReceived = false;
890 
891     // 4th polling - guarded by the heuristic to handle spurious alerting on partially filled buffer
892     EXPECT_CALL(*mockProcDiskStats, deltaSystemWideDiskStats()).WillOnce([]() -> DiskStats {
893         return DiskStats{.numKibWritten = 10};
894     });
895 
896     ASSERT_RESULT_OK(mIoOveruseMonitor->onPeriodicMonitor(nextCollectionTime(), mockProcDiskStats,
897                                                           alertHandler));
898     EXPECT_FALSE(isAlertReceived) << "Triggered spurious alert when not exceeding the threshold";
899 
900     // 5th polling exceeds second threshold
901     EXPECT_CALL(*mockProcDiskStats, deltaSystemWideDiskStats()).WillOnce([]() -> DiskStats {
902         return DiskStats{.numKibWritten = 80};
903     });
904 
905     ASSERT_RESULT_OK(mIoOveruseMonitor->onPeriodicMonitor(nextCollectionTime(), mockProcDiskStats,
906                                                           alertHandler));
907     EXPECT_TRUE(isAlertReceived) << "Failed to trigger alert when exceeding the threshold";
908 
909     isAlertReceived = false;
910 
911     // 6th polling exceeds third threshold
912     EXPECT_CALL(*mockProcDiskStats, deltaSystemWideDiskStats()).WillOnce([]() -> DiskStats {
913         return DiskStats{.numKibWritten = 10};
914     });
915 
916     ASSERT_RESULT_OK(mIoOveruseMonitor->onPeriodicMonitor(nextCollectionTime(), mockProcDiskStats,
917                                                           alertHandler));
918     EXPECT_TRUE(isAlertReceived) << "Failed to trigger alert when exceeding the threshold";
919 }
920 
TEST_F(IoOveruseMonitorTest,TestRegisterResourceOveruseListener)921 TEST_F(IoOveruseMonitorTest, TestRegisterResourceOveruseListener) {
922     sp<MockResourceOveruseListener> mockResourceOveruseListener =
923             sp<MockResourceOveruseListener>::make();
924 
925     ASSERT_RESULT_OK(mIoOveruseMonitor->addIoOveruseListener(mockResourceOveruseListener));
926 
927     ASSERT_RESULT_OK(mIoOveruseMonitor->addIoOveruseListener(mockResourceOveruseListener));
928 }
929 
TEST_F(IoOveruseMonitorTest,TestErrorsRegisterResourceOveruseListenerOnLinkToDeathError)930 TEST_F(IoOveruseMonitorTest, TestErrorsRegisterResourceOveruseListenerOnLinkToDeathError) {
931     sp<MockResourceOveruseListener> mockResourceOveruseListener =
932             sp<MockResourceOveruseListener>::make();
933 
934     mockResourceOveruseListener->injectLinkToDeathFailure();
935 
936     ASSERT_FALSE(mIoOveruseMonitor->addIoOveruseListener(mockResourceOveruseListener).ok());
937 }
938 
TEST_F(IoOveruseMonitorTest,TestUnaddIoOveruseListener)939 TEST_F(IoOveruseMonitorTest, TestUnaddIoOveruseListener) {
940     sp<MockResourceOveruseListener> mockResourceOveruseListener =
941             sp<MockResourceOveruseListener>::make();
942 
943     ASSERT_RESULT_OK(mIoOveruseMonitor->addIoOveruseListener(mockResourceOveruseListener));
944 
945     ASSERT_RESULT_OK(mIoOveruseMonitor->removeIoOveruseListener(mockResourceOveruseListener));
946 
947     ASSERT_FALSE(mIoOveruseMonitor->removeIoOveruseListener(mockResourceOveruseListener).ok())
948             << "Should error on duplicate unregister";
949 }
950 
TEST_F(IoOveruseMonitorTest,TestUnaddIoOveruseListenerOnUnlinkToDeathError)951 TEST_F(IoOveruseMonitorTest, TestUnaddIoOveruseListenerOnUnlinkToDeathError) {
952     sp<MockResourceOveruseListener> mockResourceOveruseListener =
953             sp<MockResourceOveruseListener>::make();
954 
955     ASSERT_RESULT_OK(mIoOveruseMonitor->addIoOveruseListener(mockResourceOveruseListener));
956 
957     mockResourceOveruseListener->injectUnlinkToDeathFailure();
958 
959     ASSERT_RESULT_OK(mIoOveruseMonitor->removeIoOveruseListener(mockResourceOveruseListener));
960 }
961 
TEST_F(IoOveruseMonitorTest,TestGetIoOveruseStats)962 TEST_F(IoOveruseMonitorTest, TestGetIoOveruseStats) {
963     EXPECT_CALL(*mMockUidStatsCollector, deltaStats())
964             .WillOnce(Return(
965                     constructUidStats({{1001000, {/*fgWrBytes=*/90'000, /*bgWrBytes=*/20'000}}})));
966 
967     time_t currentTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
968     const auto [startTime, durationInSeconds] = calculateStartAndDuration(currentTime);
969 
970     ASSERT_RESULT_OK(mIoOveruseMonitor->onPeriodicCollection(currentTime, SystemState::NORMAL_MODE,
971                                                              mMockUidStatsCollector, nullptr));
972 
973     const auto expected =
974             constructIoOveruseStats(/*isKillable=*/false,
975                                     /*remaining=*/
976                                     constructPerStateBytes(70'000, 20'000, 100'000),
977                                     /*written=*/
978                                     constructPerStateBytes(90'000, 20'000, 0),
979                                     /*totalOveruses=*/1, startTime, durationInSeconds);
980     IoOveruseStats actual;
981     ASSERT_NO_FATAL_FAILURE(executeAsUid(1001000, [&]() {
982         ASSERT_RESULT_OK(mIoOveruseMonitor->getIoOveruseStats(&actual));
983     }));
984     EXPECT_THAT(actual, expected) << "Expected: " << expected.toString()
985                                   << "\nActual: " << actual.toString();
986 }
987 
TEST_F(IoOveruseMonitorTest,TestResetIoOveruseStats)988 TEST_F(IoOveruseMonitorTest, TestResetIoOveruseStats) {
989     EXPECT_CALL(*mMockUidStatsCollector, deltaStats())
990             .WillOnce(Return(
991                     constructUidStats({{1001000, {/*fgWrBytes=*/90'000, /*bgWrBytes=*/20'000}}})));
992 
993     ASSERT_RESULT_OK(
994             mIoOveruseMonitor->onPeriodicCollection(std::chrono::system_clock::to_time_t(
995                                                             std::chrono::system_clock::now()),
996                                                     SystemState::NORMAL_MODE,
997                                                     mMockUidStatsCollector, nullptr));
998 
999     IoOveruseStats actual;
1000     ASSERT_NO_FATAL_FAILURE(executeAsUid(1001000, [&]() {
1001         ASSERT_RESULT_OK(mIoOveruseMonitor->getIoOveruseStats(&actual));
1002     }));
1003 
1004     EXPECT_NE(actual.totalOveruses, 0);
1005     EXPECT_NE(actual.writtenBytes.foregroundBytes, 0);
1006     EXPECT_NE(actual.writtenBytes.backgroundBytes, 0);
1007 
1008     std::vector<std::string> packageNames = {"system.daemon"};
1009     EXPECT_CALL(*mMockWatchdogServiceHelper, resetResourceOveruseStats(packageNames))
1010             .WillOnce(Return(Status::ok()));
1011 
1012     ASSERT_RESULT_OK(mIoOveruseMonitor->resetIoOveruseStats(packageNames));
1013 
1014     ASSERT_NO_FATAL_FAILURE(executeAsUid(1001000, [&]() {
1015         ASSERT_RESULT_OK(mIoOveruseMonitor->getIoOveruseStats(&actual));
1016     }));
1017 
1018     EXPECT_EQ(actual.totalOveruses, 0);
1019     EXPECT_EQ(actual.writtenBytes.foregroundBytes, 0);
1020     EXPECT_EQ(actual.writtenBytes.backgroundBytes, 0);
1021 }
1022 
TEST_F(IoOveruseMonitorTest,TestErrorsResetIoOveruseStatsOnWatchdogServiceHelperError)1023 TEST_F(IoOveruseMonitorTest, TestErrorsResetIoOveruseStatsOnWatchdogServiceHelperError) {
1024     std::vector<std::string> packageNames = {"system.daemon"};
1025     EXPECT_CALL(*mMockWatchdogServiceHelper, resetResourceOveruseStats(packageNames))
1026             .WillOnce(Return(Status::fromExceptionCode(Status::EX_ILLEGAL_STATE)));
1027 
1028     ASSERT_FALSE(mIoOveruseMonitor->resetIoOveruseStats(packageNames).ok())
1029             << "Must return error when WatchdogServiceHelper fails to reset stats";
1030 }
1031 
TEST_F(IoOveruseMonitorTest,TestErrorsGetIoOveruseStatsOnNoStats)1032 TEST_F(IoOveruseMonitorTest, TestErrorsGetIoOveruseStatsOnNoStats) {
1033     ON_CALL(*mMockPackageInfoResolver, getPackageInfosForUids(_))
1034             .WillByDefault([]() -> std::unordered_map<uid_t, PackageInfo> {
1035                 return {{1001000,
1036                          constructPackageInfo(/*packageName=*/"system.daemon", /*uid=*/1001000,
1037                                               UidType::NATIVE)}};
1038             });
1039     IoOveruseStats actual;
1040     ASSERT_NO_FATAL_FAILURE(executeAsUid(1001000, [&]() {
1041         ASSERT_FALSE(mIoOveruseMonitor->getIoOveruseStats(&actual).ok())
1042                 << "Should fail on missing I/O overuse stats";
1043     }));
1044 
1045     ASSERT_NO_FATAL_FAILURE(executeAsUid(1102001, [&]() {
1046         ASSERT_FALSE(mIoOveruseMonitor->getIoOveruseStats(&actual).ok())
1047                 << "Should fail on missing package information";
1048     }));
1049 }
1050 
TEST_F(IoOveruseMonitorTest,TestUpdateResourceOveruseConfigurations)1051 TEST_F(IoOveruseMonitorTest, TestUpdateResourceOveruseConfigurations) {
1052     EXPECT_CALL(*mMockIoOveruseConfigs, update(_)).WillOnce(Return(Result<void>{}));
1053     EXPECT_CALL(*mMockIoOveruseConfigs, writeToDisk()).WillOnce(Return(Result<void>{}));
1054 
1055     ASSERT_RESULT_OK(mIoOveruseMonitor->updateResourceOveruseConfigurations({}));
1056 }
1057 
TEST_F(IoOveruseMonitorTest,TestFailsUpdateResourceOveruseConfigurations)1058 TEST_F(IoOveruseMonitorTest, TestFailsUpdateResourceOveruseConfigurations) {
1059     EXPECT_CALL(*mMockIoOveruseConfigs, update(_))
1060             .WillOnce([&]([[maybe_unused]] const std::vector<ResourceOveruseConfiguration>& configs)
1061                               -> Result<void> { return Error() << "Failed to update"; });
1062     EXPECT_CALL(*mMockIoOveruseConfigs, writeToDisk()).Times(0);
1063 
1064     ASSERT_FALSE(mIoOveruseMonitor->updateResourceOveruseConfigurations({}).ok());
1065 }
1066 
TEST_F(IoOveruseMonitorTest,TestRemoveUser)1067 TEST_F(IoOveruseMonitorTest, TestRemoveUser) {
1068     std::vector<UserPackageIoUsageStats> todayIoUsageStats =
1069             {constructUserPackageIoUsageStats(
1070                      /*userId=*/11, "com.android.google.package",
1071                      /*writtenBytes=*/constructPerStateBytes(100'000, 85'000, 120'000),
1072                      /*forgivenWriteBytes=*/constructPerStateBytes(70'000, 60'000, 100'000),
1073                      /*totalOveruses=*/3),
1074              constructUserPackageIoUsageStats(
1075                      /*userId=*/12, "com.android.kitchensink",
1076                      /*writtenBytes=*/constructPerStateBytes(50'000, 40'000, 35'000),
1077                      /*forgivenWriteBytes=*/constructPerStateBytes(30'000, 30'000, 30'000),
1078                      /*totalOveruses=*/6)};
1079     EXPECT_CALL(*mMockWatchdogServiceHelper, getTodayIoUsageStats(_))
1080             .WillOnce(DoAll(SetArgPointee<0>(todayIoUsageStats), Return(Status::ok())));
1081 
1082     EXPECT_CALL(*mMockUidStatsCollector, deltaStats())
1083             .WillOnce(Return(
1084                     constructUidStats({{1001000, {/*fgWrBytes=*/70'000, /*bgWrBytes=*/20'000}},
1085                                        {1112345, {/*fgWrBytes=*/35'000, /*bgWrBytes=*/15'000}}})));
1086 
1087     std::vector<PackageIoOveruseStats> actualIoOveruseStats;
1088     EXPECT_CALL(*mMockWatchdogServiceHelper, latestIoOveruseStats(_))
1089             .WillOnce(DoAll(SaveArg<0>(&actualIoOveruseStats), Return(Status::ok())));
1090 
1091     time_t currentTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
1092     const auto [startTime, durationInSeconds] = calculateStartAndDuration(currentTime);
1093 
1094     ASSERT_RESULT_OK(mIoOveruseMonitor->onPeriodicCollection(currentTime, SystemState::NORMAL_MODE,
1095                                                              mMockUidStatsCollector, nullptr));
1096 
1097     std::vector<PackageIoOveruseStats> expectedIoOveruseStats =
1098             {constructPackageIoOveruseStats(
1099                      /*uid*=*/1001000, /*shouldNotify=*/false, /*isKillable=*/false,
1100                      /*remaining=*/constructPerStateBytes(10'000, 20'000, 100'000),
1101                      /*written=*/constructPerStateBytes(70'000, 20'000, 0),
1102                      /*forgiven=*/constructPerStateBytes(0, 0, 0),
1103                      /*totalOveruses=*/0, startTime, durationInSeconds),
1104              constructPackageIoOveruseStats(
1105                      /*uid*=*/1112345, /*shouldNotify=*/true, /*isKillable=*/true,
1106                      /*remaining=*/constructPerStateBytes(5'000, 0, 80'000),
1107                      /*written=*/constructPerStateBytes(135'000, 100'000, 120'000),
1108                      /*forgiven=*/constructPerStateBytes(70'000, 90'000, 100'000),
1109                      /*totalOveruses=*/4, startTime, durationInSeconds)};
1110     EXPECT_THAT(actualIoOveruseStats, UnorderedElementsAreArray(expectedIoOveruseStats))
1111             << "Expected: " << toString(expectedIoOveruseStats)
1112             << "\nActual: " << toString(actualIoOveruseStats);
1113 
1114     mIoOveruseMonitor->removeStatsForUser(/*userId=*/11);
1115     mIoOveruseMonitor->removeStatsForUser(/*userId=*/12);
1116 
1117     EXPECT_CALL(*mMockUidStatsCollector, deltaStats())
1118             .WillOnce(Return(
1119                     constructUidStats({{1112345, {/*fgWrBytes=*/70'000, /*bgWrBytes=*/40'000}},
1120                                        {1245678, {/*fgWrBytes=*/30'000, /*bgWrBytes=*/10'000}}})));
1121 
1122     actualIoOveruseStats.clear();
1123     EXPECT_CALL(*mMockWatchdogServiceHelper, latestIoOveruseStats(_))
1124             .WillOnce(DoAll(SaveArg<0>(&actualIoOveruseStats), Return(Status::ok())));
1125 
1126     ASSERT_RESULT_OK(mIoOveruseMonitor->onPeriodicCollection(currentTime, SystemState::GARAGE_MODE,
1127                                                              mMockUidStatsCollector, nullptr));
1128 
1129     expectedIoOveruseStats = {constructPackageIoOveruseStats(
1130                                       /*uid*=*/1112345, /*shouldNotify=*/true, /*isKillable=*/true,
1131                                       /*remaining=*/constructPerStateBytes(70'000, 30'000, 0),
1132                                       /*written=*/constructPerStateBytes(0, 0, 110'000),
1133                                       /*forgiven=*/constructPerStateBytes(0, 0, 100'000),
1134                                       /*totalOveruses=*/1, startTime, durationInSeconds),
1135                               constructPackageIoOveruseStats(
1136                                       /*uid*=*/1245678, /*shouldNotify=*/true, /*isKillable=*/true,
1137                                       /*remaining=*/constructPerStateBytes(30'000, 15'000, 0),
1138                                       /*written=*/constructPerStateBytes(0, 0, 40'000),
1139                                       /*forgiven=*/constructPerStateBytes(0, 0, 40'000),
1140                                       /*totalOveruses=*/4, startTime, durationInSeconds)};
1141     EXPECT_THAT(actualIoOveruseStats, UnorderedElementsAreArray(expectedIoOveruseStats))
1142             << "Expected: " << toString(expectedIoOveruseStats)
1143             << "\nActual: " << toString(actualIoOveruseStats);
1144 }
1145 
1146 }  // namespace watchdog
1147 }  // namespace automotive
1148 }  // namespace android
1149