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 "MockProcDiskStatsCollector.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 final : 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 final : public RefBase {
182 public:
IoOveruseMonitorPeer(const sp<IoOveruseMonitor> & ioOveruseMonitor)183 explicit IoOveruseMonitorPeer(const sp<IoOveruseMonitor>& ioOveruseMonitor) :
184 mIoOveruseMonitor(ioOveruseMonitor) {}
185
init(const sp<IoOveruseConfigsInterface> & ioOveruseConfigs,const sp<PackageInfoResolverInterface> & packageInfoResolver)186 Result<void> init(const sp<IoOveruseConfigsInterface>& ioOveruseConfigs,
187 const sp<PackageInfoResolverInterface>& 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 IoOveruseConfigsInterface::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<MockProcDiskStatsCollector> mockProcDiskStatsCollector =
865 sp<MockProcDiskStatsCollector>::make();
866 EXPECT_CALL(*mockProcDiskStatsCollector, deltaSystemWideDiskStats()).Times(0);
867
868 ASSERT_RESULT_OK(mIoOveruseMonitor->onPeriodicMonitor(nextCollectionTime(),
869 mockProcDiskStatsCollector,
870 alertHandler));
871 EXPECT_FALSE(isAlertReceived) << "Triggered spurious alert because first polling is ignored";
872
873 // 2nd polling - guarded by the heuristic to handle spurious alerting on partially filled buffer
874 EXPECT_CALL(*mockProcDiskStatsCollector, deltaSystemWideDiskStats())
875 .WillOnce([]() -> DiskStats { return DiskStats{.numKibWritten = 70}; });
876
877 ASSERT_RESULT_OK(mIoOveruseMonitor->onPeriodicMonitor(nextCollectionTime(),
878 mockProcDiskStatsCollector,
879 alertHandler));
880 EXPECT_FALSE(isAlertReceived) << "Triggered spurious alert when not exceeding the threshold";
881
882 // 3rd polling exceeds first threshold
883 EXPECT_CALL(*mockProcDiskStatsCollector, deltaSystemWideDiskStats())
884 .WillOnce([]() -> DiskStats { return DiskStats{.numKibWritten = 90}; });
885
886 ASSERT_RESULT_OK(mIoOveruseMonitor->onPeriodicMonitor(nextCollectionTime(),
887 mockProcDiskStatsCollector,
888 alertHandler));
889 EXPECT_TRUE(isAlertReceived) << "Failed to trigger alert when exceeding the threshold";
890
891 isAlertReceived = false;
892
893 // 4th polling - guarded by the heuristic to handle spurious alerting on partially filled buffer
894 EXPECT_CALL(*mockProcDiskStatsCollector, deltaSystemWideDiskStats())
895 .WillOnce([]() -> DiskStats { return DiskStats{.numKibWritten = 10}; });
896
897 ASSERT_RESULT_OK(mIoOveruseMonitor->onPeriodicMonitor(nextCollectionTime(),
898 mockProcDiskStatsCollector,
899 alertHandler));
900 EXPECT_FALSE(isAlertReceived) << "Triggered spurious alert when not exceeding the threshold";
901
902 // 5th polling exceeds second threshold
903 EXPECT_CALL(*mockProcDiskStatsCollector, deltaSystemWideDiskStats())
904 .WillOnce([]() -> DiskStats { return DiskStats{.numKibWritten = 80}; });
905
906 ASSERT_RESULT_OK(mIoOveruseMonitor->onPeriodicMonitor(nextCollectionTime(),
907 mockProcDiskStatsCollector,
908 alertHandler));
909 EXPECT_TRUE(isAlertReceived) << "Failed to trigger alert when exceeding the threshold";
910
911 isAlertReceived = false;
912
913 // 6th polling exceeds third threshold
914 EXPECT_CALL(*mockProcDiskStatsCollector, deltaSystemWideDiskStats())
915 .WillOnce([]() -> DiskStats { return DiskStats{.numKibWritten = 10}; });
916
917 ASSERT_RESULT_OK(mIoOveruseMonitor->onPeriodicMonitor(nextCollectionTime(),
918 mockProcDiskStatsCollector,
919 alertHandler));
920 EXPECT_TRUE(isAlertReceived) << "Failed to trigger alert when exceeding the threshold";
921 }
922
TEST_F(IoOveruseMonitorTest,TestRegisterResourceOveruseListener)923 TEST_F(IoOveruseMonitorTest, TestRegisterResourceOveruseListener) {
924 sp<MockResourceOveruseListener> mockResourceOveruseListener =
925 sp<MockResourceOveruseListener>::make();
926
927 ASSERT_RESULT_OK(mIoOveruseMonitor->addIoOveruseListener(mockResourceOveruseListener));
928
929 ASSERT_RESULT_OK(mIoOveruseMonitor->addIoOveruseListener(mockResourceOveruseListener));
930 }
931
TEST_F(IoOveruseMonitorTest,TestErrorsRegisterResourceOveruseListenerOnLinkToDeathError)932 TEST_F(IoOveruseMonitorTest, TestErrorsRegisterResourceOveruseListenerOnLinkToDeathError) {
933 sp<MockResourceOveruseListener> mockResourceOveruseListener =
934 sp<MockResourceOveruseListener>::make();
935
936 mockResourceOveruseListener->injectLinkToDeathFailure();
937
938 ASSERT_FALSE(mIoOveruseMonitor->addIoOveruseListener(mockResourceOveruseListener).ok());
939 }
940
TEST_F(IoOveruseMonitorTest,TestUnaddIoOveruseListener)941 TEST_F(IoOveruseMonitorTest, TestUnaddIoOveruseListener) {
942 sp<MockResourceOveruseListener> mockResourceOveruseListener =
943 sp<MockResourceOveruseListener>::make();
944
945 ASSERT_RESULT_OK(mIoOveruseMonitor->addIoOveruseListener(mockResourceOveruseListener));
946
947 ASSERT_RESULT_OK(mIoOveruseMonitor->removeIoOveruseListener(mockResourceOveruseListener));
948
949 ASSERT_FALSE(mIoOveruseMonitor->removeIoOveruseListener(mockResourceOveruseListener).ok())
950 << "Should error on duplicate unregister";
951 }
952
TEST_F(IoOveruseMonitorTest,TestUnaddIoOveruseListenerOnUnlinkToDeathError)953 TEST_F(IoOveruseMonitorTest, TestUnaddIoOveruseListenerOnUnlinkToDeathError) {
954 sp<MockResourceOveruseListener> mockResourceOveruseListener =
955 sp<MockResourceOveruseListener>::make();
956
957 ASSERT_RESULT_OK(mIoOveruseMonitor->addIoOveruseListener(mockResourceOveruseListener));
958
959 mockResourceOveruseListener->injectUnlinkToDeathFailure();
960
961 ASSERT_RESULT_OK(mIoOveruseMonitor->removeIoOveruseListener(mockResourceOveruseListener));
962 }
963
TEST_F(IoOveruseMonitorTest,TestGetIoOveruseStats)964 TEST_F(IoOveruseMonitorTest, TestGetIoOveruseStats) {
965 EXPECT_CALL(*mMockUidStatsCollector, deltaStats())
966 .WillOnce(Return(
967 constructUidStats({{1001000, {/*fgWrBytes=*/90'000, /*bgWrBytes=*/20'000}}})));
968
969 time_t currentTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
970 const auto [startTime, durationInSeconds] = calculateStartAndDuration(currentTime);
971
972 ASSERT_RESULT_OK(mIoOveruseMonitor->onPeriodicCollection(currentTime, SystemState::NORMAL_MODE,
973 mMockUidStatsCollector, nullptr));
974
975 const auto expected =
976 constructIoOveruseStats(/*isKillable=*/false,
977 /*remaining=*/
978 constructPerStateBytes(70'000, 20'000, 100'000),
979 /*written=*/
980 constructPerStateBytes(90'000, 20'000, 0),
981 /*totalOveruses=*/1, startTime, durationInSeconds);
982 IoOveruseStats actual;
983 ASSERT_NO_FATAL_FAILURE(executeAsUid(1001000, [&]() {
984 ASSERT_RESULT_OK(mIoOveruseMonitor->getIoOveruseStats(&actual));
985 }));
986 EXPECT_THAT(actual, expected) << "Expected: " << expected.toString()
987 << "\nActual: " << actual.toString();
988 }
989
TEST_F(IoOveruseMonitorTest,TestResetIoOveruseStats)990 TEST_F(IoOveruseMonitorTest, TestResetIoOveruseStats) {
991 EXPECT_CALL(*mMockUidStatsCollector, deltaStats())
992 .WillOnce(Return(
993 constructUidStats({{1001000, {/*fgWrBytes=*/90'000, /*bgWrBytes=*/20'000}}})));
994
995 ASSERT_RESULT_OK(
996 mIoOveruseMonitor->onPeriodicCollection(std::chrono::system_clock::to_time_t(
997 std::chrono::system_clock::now()),
998 SystemState::NORMAL_MODE,
999 mMockUidStatsCollector, nullptr));
1000
1001 IoOveruseStats actual;
1002 ASSERT_NO_FATAL_FAILURE(executeAsUid(1001000, [&]() {
1003 ASSERT_RESULT_OK(mIoOveruseMonitor->getIoOveruseStats(&actual));
1004 }));
1005
1006 EXPECT_NE(actual.totalOveruses, 0);
1007 EXPECT_NE(actual.writtenBytes.foregroundBytes, 0);
1008 EXPECT_NE(actual.writtenBytes.backgroundBytes, 0);
1009
1010 std::vector<std::string> packageNames = {"system.daemon"};
1011 EXPECT_CALL(*mMockWatchdogServiceHelper, resetResourceOveruseStats(packageNames))
1012 .WillOnce(Return(Status::ok()));
1013
1014 ASSERT_RESULT_OK(mIoOveruseMonitor->resetIoOveruseStats(packageNames));
1015
1016 ASSERT_NO_FATAL_FAILURE(executeAsUid(1001000, [&]() {
1017 ASSERT_RESULT_OK(mIoOveruseMonitor->getIoOveruseStats(&actual));
1018 }));
1019
1020 EXPECT_EQ(actual.totalOveruses, 0);
1021 EXPECT_EQ(actual.writtenBytes.foregroundBytes, 0);
1022 EXPECT_EQ(actual.writtenBytes.backgroundBytes, 0);
1023 }
1024
TEST_F(IoOveruseMonitorTest,TestErrorsResetIoOveruseStatsOnWatchdogServiceHelperError)1025 TEST_F(IoOveruseMonitorTest, TestErrorsResetIoOveruseStatsOnWatchdogServiceHelperError) {
1026 std::vector<std::string> packageNames = {"system.daemon"};
1027 EXPECT_CALL(*mMockWatchdogServiceHelper, resetResourceOveruseStats(packageNames))
1028 .WillOnce(Return(Status::fromExceptionCode(Status::EX_ILLEGAL_STATE)));
1029
1030 ASSERT_FALSE(mIoOveruseMonitor->resetIoOveruseStats(packageNames).ok())
1031 << "Must return error when WatchdogServiceHelper fails to reset stats";
1032 }
1033
TEST_F(IoOveruseMonitorTest,TestErrorsGetIoOveruseStatsOnNoStats)1034 TEST_F(IoOveruseMonitorTest, TestErrorsGetIoOveruseStatsOnNoStats) {
1035 ON_CALL(*mMockPackageInfoResolver, getPackageInfosForUids(_))
1036 .WillByDefault([]() -> std::unordered_map<uid_t, PackageInfo> {
1037 return {{1001000,
1038 constructPackageInfo(/*packageName=*/"system.daemon", /*uid=*/1001000,
1039 UidType::NATIVE)}};
1040 });
1041 IoOveruseStats actual;
1042 ASSERT_NO_FATAL_FAILURE(executeAsUid(1001000, [&]() {
1043 ASSERT_FALSE(mIoOveruseMonitor->getIoOveruseStats(&actual).ok())
1044 << "Should fail on missing I/O overuse stats";
1045 }));
1046
1047 ASSERT_NO_FATAL_FAILURE(executeAsUid(1102001, [&]() {
1048 ASSERT_FALSE(mIoOveruseMonitor->getIoOveruseStats(&actual).ok())
1049 << "Should fail on missing package information";
1050 }));
1051 }
1052
TEST_F(IoOveruseMonitorTest,TestUpdateResourceOveruseConfigurations)1053 TEST_F(IoOveruseMonitorTest, TestUpdateResourceOveruseConfigurations) {
1054 EXPECT_CALL(*mMockIoOveruseConfigs, update(_)).WillOnce(Return(Result<void>{}));
1055 EXPECT_CALL(*mMockIoOveruseConfigs, writeToDisk()).WillOnce(Return(Result<void>{}));
1056
1057 ASSERT_RESULT_OK(mIoOveruseMonitor->updateResourceOveruseConfigurations({}));
1058 }
1059
TEST_F(IoOveruseMonitorTest,TestFailsUpdateResourceOveruseConfigurations)1060 TEST_F(IoOveruseMonitorTest, TestFailsUpdateResourceOveruseConfigurations) {
1061 EXPECT_CALL(*mMockIoOveruseConfigs, update(_))
1062 .WillOnce([&]([[maybe_unused]] const std::vector<ResourceOveruseConfiguration>& configs)
1063 -> Result<void> { return Error() << "Failed to update"; });
1064 EXPECT_CALL(*mMockIoOveruseConfigs, writeToDisk()).Times(0);
1065
1066 ASSERT_FALSE(mIoOveruseMonitor->updateResourceOveruseConfigurations({}).ok());
1067 }
1068
TEST_F(IoOveruseMonitorTest,TestRemoveUser)1069 TEST_F(IoOveruseMonitorTest, TestRemoveUser) {
1070 std::vector<UserPackageIoUsageStats> todayIoUsageStats =
1071 {constructUserPackageIoUsageStats(
1072 /*userId=*/11, "com.android.google.package",
1073 /*writtenBytes=*/constructPerStateBytes(100'000, 85'000, 120'000),
1074 /*forgivenWriteBytes=*/constructPerStateBytes(70'000, 60'000, 100'000),
1075 /*totalOveruses=*/3),
1076 constructUserPackageIoUsageStats(
1077 /*userId=*/12, "com.android.kitchensink",
1078 /*writtenBytes=*/constructPerStateBytes(50'000, 40'000, 35'000),
1079 /*forgivenWriteBytes=*/constructPerStateBytes(30'000, 30'000, 30'000),
1080 /*totalOveruses=*/6)};
1081 EXPECT_CALL(*mMockWatchdogServiceHelper, getTodayIoUsageStats(_))
1082 .WillOnce(DoAll(SetArgPointee<0>(todayIoUsageStats), Return(Status::ok())));
1083
1084 EXPECT_CALL(*mMockUidStatsCollector, deltaStats())
1085 .WillOnce(Return(
1086 constructUidStats({{1001000, {/*fgWrBytes=*/70'000, /*bgWrBytes=*/20'000}},
1087 {1112345, {/*fgWrBytes=*/35'000, /*bgWrBytes=*/15'000}}})));
1088
1089 std::vector<PackageIoOveruseStats> actualIoOveruseStats;
1090 EXPECT_CALL(*mMockWatchdogServiceHelper, latestIoOveruseStats(_))
1091 .WillOnce(DoAll(SaveArg<0>(&actualIoOveruseStats), Return(Status::ok())));
1092
1093 time_t currentTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
1094 const auto [startTime, durationInSeconds] = calculateStartAndDuration(currentTime);
1095
1096 ASSERT_RESULT_OK(mIoOveruseMonitor->onPeriodicCollection(currentTime, SystemState::NORMAL_MODE,
1097 mMockUidStatsCollector, nullptr));
1098
1099 std::vector<PackageIoOveruseStats> expectedIoOveruseStats =
1100 {constructPackageIoOveruseStats(
1101 /*uid*=*/1001000, /*shouldNotify=*/false, /*isKillable=*/false,
1102 /*remaining=*/constructPerStateBytes(10'000, 20'000, 100'000),
1103 /*written=*/constructPerStateBytes(70'000, 20'000, 0),
1104 /*forgiven=*/constructPerStateBytes(0, 0, 0),
1105 /*totalOveruses=*/0, startTime, durationInSeconds),
1106 constructPackageIoOveruseStats(
1107 /*uid*=*/1112345, /*shouldNotify=*/true, /*isKillable=*/true,
1108 /*remaining=*/constructPerStateBytes(5'000, 0, 80'000),
1109 /*written=*/constructPerStateBytes(135'000, 100'000, 120'000),
1110 /*forgiven=*/constructPerStateBytes(70'000, 90'000, 100'000),
1111 /*totalOveruses=*/4, startTime, durationInSeconds)};
1112 EXPECT_THAT(actualIoOveruseStats, UnorderedElementsAreArray(expectedIoOveruseStats))
1113 << "Expected: " << toString(expectedIoOveruseStats)
1114 << "\nActual: " << toString(actualIoOveruseStats);
1115
1116 mIoOveruseMonitor->removeStatsForUser(/*userId=*/11);
1117 mIoOveruseMonitor->removeStatsForUser(/*userId=*/12);
1118
1119 EXPECT_CALL(*mMockUidStatsCollector, deltaStats())
1120 .WillOnce(Return(
1121 constructUidStats({{1112345, {/*fgWrBytes=*/70'000, /*bgWrBytes=*/40'000}},
1122 {1245678, {/*fgWrBytes=*/30'000, /*bgWrBytes=*/10'000}}})));
1123
1124 actualIoOveruseStats.clear();
1125 EXPECT_CALL(*mMockWatchdogServiceHelper, latestIoOveruseStats(_))
1126 .WillOnce(DoAll(SaveArg<0>(&actualIoOveruseStats), Return(Status::ok())));
1127
1128 ASSERT_RESULT_OK(mIoOveruseMonitor->onPeriodicCollection(currentTime, SystemState::GARAGE_MODE,
1129 mMockUidStatsCollector, nullptr));
1130
1131 expectedIoOveruseStats = {constructPackageIoOveruseStats(
1132 /*uid*=*/1112345, /*shouldNotify=*/true, /*isKillable=*/true,
1133 /*remaining=*/constructPerStateBytes(70'000, 30'000, 0),
1134 /*written=*/constructPerStateBytes(0, 0, 110'000),
1135 /*forgiven=*/constructPerStateBytes(0, 0, 100'000),
1136 /*totalOveruses=*/1, startTime, durationInSeconds),
1137 constructPackageIoOveruseStats(
1138 /*uid*=*/1245678, /*shouldNotify=*/true, /*isKillable=*/true,
1139 /*remaining=*/constructPerStateBytes(30'000, 15'000, 0),
1140 /*written=*/constructPerStateBytes(0, 0, 40'000),
1141 /*forgiven=*/constructPerStateBytes(0, 0, 40'000),
1142 /*totalOveruses=*/4, startTime, durationInSeconds)};
1143 EXPECT_THAT(actualIoOveruseStats, UnorderedElementsAreArray(expectedIoOveruseStats))
1144 << "Expected: " << toString(expectedIoOveruseStats)
1145 << "\nActual: " << toString(actualIoOveruseStats);
1146 }
1147
1148 } // namespace watchdog
1149 } // namespace automotive
1150 } // namespace android
1151