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