aboutsummaryrefslogtreecommitdiff
path: root/cpp/watchdog
diff options
context:
space:
mode:
authorLakshman Annadorai <lakshmana@google.com>2021-10-08 18:39:10 +0000
committerLakshman Annadorai <lakshmana@google.com>2021-10-15 02:12:28 +0000
commit03cbd1f7828332340d15d1eed25ba2cfb4fd35cb (patch)
tree4f1ae32e542b914468f6103e66667e9245cea557 /cpp/watchdog
parent2b802eeaee7f374eb10a78dc93ec5291b76156e4 (diff)
downloadCar-03cbd1f7828332340d15d1eed25ba2cfb4fd35cb.tar.gz
Fetch today's I/O usage stats collected during previous boot.
Watchdog daemon fetches today's I/O usage stat, that were collected during the previous boot, from CarWatchdogService, so the daemon can the have the aggregated view of the total bytes written to disk since the beginning of the day. Test: atest CarWatchdogServiceUnitTest WatchdogStorageUnitTest libwatchdog_test Bug: 192665981 Change-Id: Ieb3f3ba27d4d94f68f94788a364007fbc022a872 Merged-In: Ieb3f3ba27d4d94f68f94788a364007fbc022a872 (cherry picked from commit 766a91829ffdb341a6d59ed65e7e0d2f38273357)
Diffstat (limited to 'cpp/watchdog')
-rw-r--r--cpp/watchdog/aidl/android/automotive/watchdog/internal/ICarWatchdogServiceForSystem.aidl7
-rw-r--r--cpp/watchdog/aidl/android/automotive/watchdog/internal/IoUsageStats.aidl39
-rw-r--r--cpp/watchdog/aidl/android/automotive/watchdog/internal/PackageIdentifier.aidl2
-rw-r--r--cpp/watchdog/aidl/android/automotive/watchdog/internal/UserPackageIoUsageStats.aidl39
-rw-r--r--cpp/watchdog/server/src/IoOveruseMonitor.cpp71
-rw-r--r--cpp/watchdog/server/src/IoOveruseMonitor.h13
-rw-r--r--cpp/watchdog/server/src/WatchdogServiceHelper.cpp12
-rw-r--r--cpp/watchdog/server/src/WatchdogServiceHelper.h6
-rw-r--r--cpp/watchdog/server/tests/IoOveruseMonitorTest.cpp141
-rw-r--r--cpp/watchdog/server/tests/MockCarWatchdogServiceForSystem.h3
-rw-r--r--cpp/watchdog/server/tests/MockWatchdogServiceHelper.h3
-rw-r--r--cpp/watchdog/server/tests/WatchdogServiceHelperTest.cpp64
12 files changed, 387 insertions, 13 deletions
diff --git a/cpp/watchdog/aidl/android/automotive/watchdog/internal/ICarWatchdogServiceForSystem.aidl b/cpp/watchdog/aidl/android/automotive/watchdog/internal/ICarWatchdogServiceForSystem.aidl
index c0cfd23444..8f36fadcac 100644
--- a/cpp/watchdog/aidl/android/automotive/watchdog/internal/ICarWatchdogServiceForSystem.aidl
+++ b/cpp/watchdog/aidl/android/automotive/watchdog/internal/ICarWatchdogServiceForSystem.aidl
@@ -19,6 +19,7 @@ package android.automotive.watchdog.internal;
import android.automotive.watchdog.internal.PackageInfo;
import android.automotive.watchdog.internal.PackageIoOveruseStats;
import android.automotive.watchdog.internal.TimeoutLength;
+import android.automotive.watchdog.internal.UserPackageIoUsageStats;
/**
* ICarWatchdogServiceForSystem interface used by the watchdog server to communicate with the
@@ -69,4 +70,10 @@ interface ICarWatchdogServiceForSystem {
* @param packageNames Package names for which to reset the stats.
*/
oneway void resetResourceOveruseStats(in @utf8InCpp List<String> packageNames);
+
+ /**
+ * Fetches today's I/O usage stats for all packages collected during the
+ * previous boot.
+ */
+ List<UserPackageIoUsageStats> getTodayIoUsageStats();
}
diff --git a/cpp/watchdog/aidl/android/automotive/watchdog/internal/IoUsageStats.aidl b/cpp/watchdog/aidl/android/automotive/watchdog/internal/IoUsageStats.aidl
new file mode 100644
index 0000000000..468ca99b3f
--- /dev/null
+++ b/cpp/watchdog/aidl/android/automotive/watchdog/internal/IoUsageStats.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.automotive.watchdog.internal;
+
+import android.automotive.watchdog.PerStateBytes;
+
+/**
+ * Structure that describes the I/O usage stats.
+ */
+parcelable IoUsageStats {
+ /**
+ * Total number of bytes written to disk.
+ */
+ PerStateBytes writtenBytes;
+
+ /**
+ * Number of bytes written to disk but forgiven.
+ */
+ PerStateBytes forgivenWriteBytes;
+
+ /**
+ * Total number of overuses.
+ */
+ int totalOveruses;
+}
diff --git a/cpp/watchdog/aidl/android/automotive/watchdog/internal/PackageIdentifier.aidl b/cpp/watchdog/aidl/android/automotive/watchdog/internal/PackageIdentifier.aidl
index c0dd86eecb..b4ff4c1a69 100644
--- a/cpp/watchdog/aidl/android/automotive/watchdog/internal/PackageIdentifier.aidl
+++ b/cpp/watchdog/aidl/android/automotive/watchdog/internal/PackageIdentifier.aidl
@@ -21,7 +21,7 @@ package android.automotive.watchdog.internal;
*/
parcelable PackageIdentifier {
/**
- * Name of the package.
+ * Generic name of the package.
*/
@utf8InCpp String name;
diff --git a/cpp/watchdog/aidl/android/automotive/watchdog/internal/UserPackageIoUsageStats.aidl b/cpp/watchdog/aidl/android/automotive/watchdog/internal/UserPackageIoUsageStats.aidl
new file mode 100644
index 0000000000..fb867e6bc8
--- /dev/null
+++ b/cpp/watchdog/aidl/android/automotive/watchdog/internal/UserPackageIoUsageStats.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.automotive.watchdog.internal;
+
+import android.automotive.watchdog.internal.IoUsageStats;
+
+/**
+ * Structure that describes the I/O usage stats for a user package.
+ */
+parcelable UserPackageIoUsageStats {
+ /**
+ * User ID for the package.
+ */
+ int userId;
+
+ /**
+ * Generic name of the package whose stats are recorded in this parcelable.
+ */
+ @utf8InCpp String packageName;
+
+ /**
+ * I/O overuse stats for the package.
+ */
+ IoUsageStats ioUsageStats;
+}
diff --git a/cpp/watchdog/server/src/IoOveruseMonitor.cpp b/cpp/watchdog/server/src/IoOveruseMonitor.cpp
index 23e14ee63e..9d40f8ba50 100644
--- a/cpp/watchdog/server/src/IoOveruseMonitor.cpp
+++ b/cpp/watchdog/server/src/IoOveruseMonitor.cpp
@@ -40,16 +40,20 @@ namespace android {
namespace automotive {
namespace watchdog {
+namespace {
+
using ::android::IPCThreadState;
using ::android::sp;
using ::android::automotive::watchdog::internal::ComponentType;
using ::android::automotive::watchdog::internal::IoOveruseConfiguration;
+using ::android::automotive::watchdog::internal::IoUsageStats;
using ::android::automotive::watchdog::internal::PackageIdentifier;
using ::android::automotive::watchdog::internal::PackageInfo;
using ::android::automotive::watchdog::internal::PackageIoOveruseStats;
using ::android::automotive::watchdog::internal::PackageResourceOveruseAction;
using ::android::automotive::watchdog::internal::ResourceOveruseConfiguration;
using ::android::automotive::watchdog::internal::UidType;
+using ::android::automotive::watchdog::internal::UserPackageIoUsageStats;
using ::android::base::Error;
using ::android::base::Result;
using ::android::base::WriteStringToFd;
@@ -66,10 +70,25 @@ constexpr const char* kHelpText =
"%s <package name>, <package name>,...: Reset resource overuse stats for the given package "
"names. Value for this flag is a comma-separated value containing package names.\n";
-namespace {
+std::string uniquePackageIdStr(const std::string& name, userid_t userId) {
+ return StringPrintf("%s:%" PRId32, name.c_str(), userId);
+}
std::string uniquePackageIdStr(const PackageIdentifier& id) {
- return StringPrintf("%s:%" PRId32, id.name.c_str(), multiuser_get_user_id(id.uid));
+ return uniquePackageIdStr(id.name, multiuser_get_user_id(id.uid));
+}
+
+PerStateBytes sum(const PerStateBytes& lhs, const PerStateBytes& rhs) {
+ const auto sum = [](const int64_t& l, const int64_t& r) -> int64_t {
+ return (std::numeric_limits<int64_t>::max() - l) > r ? (l + r)
+ : std::numeric_limits<int64_t>::max();
+ };
+
+ PerStateBytes result;
+ result.foregroundBytes = sum(lhs.foregroundBytes, rhs.foregroundBytes);
+ result.backgroundBytes = sum(lhs.backgroundBytes, rhs.backgroundBytes);
+ result.garageModeBytes = sum(lhs.garageModeBytes, rhs.garageModeBytes);
+ return result;
}
PerStateBytes diff(const PerStateBytes& lhs, const PerStateBytes& rhs) {
@@ -116,6 +135,7 @@ IoOveruseMonitor::IoOveruseMonitor(
const android::sp<IWatchdogServiceHelper>& watchdogServiceHelper) :
mMinSyncWrittenBytes(kMinSyncWrittenBytes),
mWatchdogServiceHelper(watchdogServiceHelper),
+ mDidReadTodayPrevBootStats(false),
mSystemWideWrittenBytes({}),
mPeriodicMonitorBufferSize(0),
mLastSystemWideIoMonitorTime(0),
@@ -179,6 +199,9 @@ Result<void> IoOveruseMonitor::onPeriodicCollection(
}
std::unique_lock writeLock(mRwMutex);
+ if (!mDidReadTodayPrevBootStats) {
+ syncTodayIoUsageStatsLocked();
+ }
struct tm prevGmt, curGmt;
gmtime_r(&mLastUserPackageIoMonitorTime, &prevGmt);
gmtime_r(&time, &curGmt);
@@ -216,6 +239,11 @@ Result<void> IoOveruseMonitor::onPeriodicCollection(
cachedUsage->second += curUsage;
dailyIoUsage = &cachedUsage->second;
} else {
+ if (auto prevBootStats = mPrevBootIoUsageStatsById.find(curUsage.id());
+ prevBootStats != mPrevBootIoUsageStatsById.end()) {
+ curUsage += prevBootStats->second;
+ mPrevBootIoUsageStatsById.erase(prevBootStats);
+ }
const auto& [it, wasInserted] = mUserPackageDailyIoUsageById.insert(
std::pair(curUsage.id(), std::move(curUsage)));
dailyIoUsage = &it->second;
@@ -380,6 +408,27 @@ bool IoOveruseMonitor::dumpHelpText(int fd) const {
fd);
}
+void IoOveruseMonitor::syncTodayIoUsageStatsLocked() {
+ std::vector<UserPackageIoUsageStats> userPackageIoUsageStats;
+ if (const auto status = mWatchdogServiceHelper->getTodayIoUsageStats(&userPackageIoUsageStats);
+ !status.isOk()) {
+ ALOGE("Failed to fetch today I/O usage stats collected during previous boot: %s",
+ status.exceptionMessage().c_str());
+ return;
+ }
+ for (const auto& statsEntry : userPackageIoUsageStats) {
+ std::string uniqueId = uniquePackageIdStr(statsEntry.packageName,
+ static_cast<userid_t>(statsEntry.userId));
+ if (auto it = mUserPackageDailyIoUsageById.find(uniqueId);
+ it != mUserPackageDailyIoUsageById.end()) {
+ it->second += statsEntry.ioUsageStats;
+ continue;
+ }
+ mPrevBootIoUsageStatsById.insert(std::pair(uniqueId, statsEntry.ioUsageStats));
+ }
+ mDidReadTodayPrevBootStats = true;
+}
+
void IoOveruseMonitor::notifyNativePackagesLocked(
const std::unordered_map<uid_t, IoOveruseStats>& statsByUid) {
for (const auto& [uid, ioOveruseStats] : statsByUid) {
@@ -585,17 +634,15 @@ IoOveruseMonitor::UserPackageIoUsage& IoOveruseMonitor::UserPackageIoUsage::oper
if (id() == r.id()) {
packageInfo = r.packageInfo;
}
- const auto sum = [](const int64_t& l, const int64_t& r) -> int64_t {
- return (std::numeric_limits<int64_t>::max() - l) > r ? (l + r)
- : std::numeric_limits<int64_t>::max();
- };
- writtenBytes.foregroundBytes =
- sum(writtenBytes.foregroundBytes, r.writtenBytes.foregroundBytes);
- writtenBytes.backgroundBytes =
- sum(writtenBytes.backgroundBytes, r.writtenBytes.backgroundBytes);
- writtenBytes.garageModeBytes =
- sum(writtenBytes.garageModeBytes, r.writtenBytes.garageModeBytes);
+ writtenBytes = sum(writtenBytes, r.writtenBytes);
+ return *this;
+}
+IoOveruseMonitor::UserPackageIoUsage& IoOveruseMonitor::UserPackageIoUsage::operator+=(
+ const IoUsageStats& ioUsageStats) {
+ writtenBytes = sum(writtenBytes, ioUsageStats.writtenBytes);
+ forgivenWriteBytes = sum(forgivenWriteBytes, ioUsageStats.forgivenWriteBytes);
+ totalOveruses += ioUsageStats.totalOveruses;
return *this;
}
diff --git a/cpp/watchdog/server/src/IoOveruseMonitor.h b/cpp/watchdog/server/src/IoOveruseMonitor.h
index df7ff609a3..57c01c08aa 100644
--- a/cpp/watchdog/server/src/IoOveruseMonitor.h
+++ b/cpp/watchdog/server/src/IoOveruseMonitor.h
@@ -193,6 +193,8 @@ private:
uint64_t lastSyncedWrittenBytes = 0;
UserPackageIoUsage& operator+=(const UserPackageIoUsage& r);
+ UserPackageIoUsage& operator+=(
+ const android::automotive::watchdog::internal::IoUsageStats& r);
const std::string id() const;
void resetStats();
@@ -214,6 +216,8 @@ private:
private:
bool isInitializedLocked() const { return mIoOveruseConfigs != nullptr; }
+ void syncTodayIoUsageStatsLocked();
+
void notifyNativePackagesLocked(const std::unordered_map<uid_t, IoOveruseStats>& statsByUid);
void handleBinderDeath(const wp<IBinder>& who);
@@ -237,6 +241,10 @@ private:
// Makes sure only one collection is running at any given time.
mutable std::shared_mutex mRwMutex;
+ // Indicates whether or not today's I/O usage stats, that were collected during previous boot,
+ // are read from CarService because CarService persists these stats in database across reboot.
+ bool mDidReadTodayPrevBootStats GUARDED_BY(mRwMutex);
+
// Summary of configs available for all the components and system-wide overuse alert thresholds.
sp<IIoOveruseConfigs> mIoOveruseConfigs GUARDED_BY(mRwMutex);
@@ -248,6 +256,11 @@ private:
size_t mPeriodicMonitorBufferSize GUARDED_BY(mRwMutex);
time_t mLastSystemWideIoMonitorTime GUARDED_BY(mRwMutex);
+ // Cache of I/O usage stats from previous boot that happened today. Key is a unique ID with
+ // the format `packageName:userId`.
+ std::unordered_map<std::string, android::automotive::watchdog::internal::IoUsageStats>
+ mPrevBootIoUsageStatsById GUARDED_BY(mRwMutex);
+
// Cache of per user package I/O usage. Key is a unique ID with the format `packageName:userId`.
std::unordered_map<std::string, UserPackageIoUsage> mUserPackageDailyIoUsageById
GUARDED_BY(mRwMutex);
diff --git a/cpp/watchdog/server/src/WatchdogServiceHelper.cpp b/cpp/watchdog/server/src/WatchdogServiceHelper.cpp
index 4c1258ffb6..702ad95cf5 100644
--- a/cpp/watchdog/server/src/WatchdogServiceHelper.cpp
+++ b/cpp/watchdog/server/src/WatchdogServiceHelper.cpp
@@ -32,6 +32,7 @@ using aawi::BnCarWatchdogServiceForSystem;
using aawi::ICarWatchdogServiceForSystem;
using aawi::PackageInfo;
using aawi::PackageIoOveruseStats;
+using aawi::UserPackageIoUsageStats;
using ::android::IBinder;
using ::android::sp;
using ::android::wp;
@@ -214,6 +215,17 @@ Status WatchdogServiceHelper::resetResourceOveruseStats(
return service->resetResourceOveruseStats(packageNames);
}
+Status WatchdogServiceHelper::getTodayIoUsageStats(
+ std::vector<UserPackageIoUsageStats>* userPackageIoUsageStats) {
+ sp<ICarWatchdogServiceForSystem> service;
+ if (std::shared_lock readLock(mRWMutex); mService == nullptr) {
+ return fromExceptionCode(Status::EX_ILLEGAL_STATE, "Watchdog service is not initialized");
+ } else {
+ service = mService;
+ }
+ return service->getTodayIoUsageStats(userPackageIoUsageStats);
+}
+
} // namespace watchdog
} // namespace automotive
} // namespace android
diff --git a/cpp/watchdog/server/src/WatchdogServiceHelper.h b/cpp/watchdog/server/src/WatchdogServiceHelper.h
index 390013a3de..eb25c6da43 100644
--- a/cpp/watchdog/server/src/WatchdogServiceHelper.h
+++ b/cpp/watchdog/server/src/WatchdogServiceHelper.h
@@ -70,6 +70,9 @@ public:
packageIoOveruseStats) = 0;
virtual android::binder::Status resetResourceOveruseStats(
const std::vector<std::string>& packageNames) = 0;
+ virtual android::binder::Status getTodayIoUsageStats(
+ std::vector<android::automotive::watchdog::internal::UserPackageIoUsageStats>*
+ userPackageIoUsageStats) = 0;
protected:
virtual android::base::Result<void> init(
@@ -110,6 +113,9 @@ public:
const std::vector<android::automotive::watchdog::internal::PackageIoOveruseStats>&
packageIoOveruseStats);
android::binder::Status resetResourceOveruseStats(const std::vector<std::string>& packageNames);
+ android::binder::Status getTodayIoUsageStats(
+ std::vector<android::automotive::watchdog::internal::UserPackageIoUsageStats>*
+ userPackageIoUsageStats);
protected:
android::base::Result<void> init(
diff --git a/cpp/watchdog/server/tests/IoOveruseMonitorTest.cpp b/cpp/watchdog/server/tests/IoOveruseMonitorTest.cpp
index 76f3cbbeaf..f4dad98ef7 100644
--- a/cpp/watchdog/server/tests/IoOveruseMonitorTest.cpp
+++ b/cpp/watchdog/server/tests/IoOveruseMonitorTest.cpp
@@ -44,6 +44,7 @@ using ::android::automotive::watchdog::internal::PackageInfo;
using ::android::automotive::watchdog::internal::PackageIoOveruseStats;
using ::android::automotive::watchdog::internal::ResourceOveruseConfiguration;
using ::android::automotive::watchdog::internal::UidType;
+using ::android::automotive::watchdog::internal::UserPackageIoUsageStats;
using ::android::base::Error;
using ::android::base::Result;
using ::android::base::StringAppendF;
@@ -54,6 +55,7 @@ using ::testing::Eq;
using ::testing::Return;
using ::testing::ReturnRef;
using ::testing::SaveArg;
+using ::testing::SetArgPointee;
using ::testing::UnorderedElementsAreArray;
namespace {
@@ -120,6 +122,20 @@ PackageIoOveruseStats constructPackageIoOveruseStats(
return stats;
}
+UserPackageIoUsageStats constructUserPackageIoUsageStats(userid_t userId,
+ const std::string& packageName,
+ const PerStateBytes& writtenBytes,
+ const PerStateBytes& forgivenWriteBytes,
+ int32_t totalOveruses) {
+ UserPackageIoUsageStats stats;
+ stats.userId = userId;
+ stats.packageName = packageName;
+ stats.ioUsageStats.writtenBytes = writtenBytes;
+ stats.ioUsageStats.forgivenWriteBytes = forgivenWriteBytes;
+ stats.ioUsageStats.totalOveruses = totalOveruses;
+ return stats;
+}
+
class ScopedChangeCallingUid : public RefBase {
public:
explicit ScopedChangeCallingUid(uid_t uid) {
@@ -219,6 +235,10 @@ protected:
{constructPerStateBytes(/*fgBytes=*/70'000, /*bgBytes=*/30'000,
/*gmBytes=*/100'000),
/*isSafeToKill=*/true}},
+ {"com.android.kitchensink",
+ {constructPerStateBytes(/*fgBytes=*/30'000, /*bgBytes=*/15'000,
+ /*gmBytes=*/10'000),
+ /*isSafeToKill=*/true}},
});
}
@@ -229,6 +249,8 @@ protected:
PackageInfo packageInfo;
if (kPackageInfosByUid.find(uid) != kPackageInfosByUid.end()) {
packageInfo = kPackageInfosByUid.at(uid);
+ } else {
+ packageInfo.packageIdentifier.uid = uid;
}
uidStats.push_back(UidStats{.packageInfo = packageInfo,
.ioStats = {/*fgRdBytes=*/989'000,
@@ -272,6 +294,10 @@ const std::unordered_map<uid_t, PackageInfo> IoOveruseMonitorTest::kPackageInfos
constructPackageInfo(
/*packageName=*/"com.android.google.package",
/*uid=*/1212345, UidType::APPLICATION)},
+ {1245678,
+ constructPackageInfo(
+ /*packageName=*/"com.android.kitchensink",
+ /*uid=*/1245678, UidType::APPLICATION)},
{1312345,
constructPackageInfo(
/*packageName=*/"com.android.google.package",
@@ -605,6 +631,121 @@ TEST_F(IoOveruseMonitorTest, TestOnPeriodicCollectionWithNoPackageInfo) {
mMockUidStatsCollector, nullptr));
}
+TEST_F(IoOveruseMonitorTest, TestOnPeriodicCollectionWithPrevBootStats) {
+ std::vector<UserPackageIoUsageStats> todayIoUsageStats =
+ {constructUserPackageIoUsageStats(
+ /*userId=*/11, "com.android.google.package",
+ /*writtenBytes=*/constructPerStateBytes(100'000, 85'000, 120'000),
+ /*forgivenWriteBytes=*/constructPerStateBytes(70'000, 60'000, 100'000),
+ /*totalOveruses=*/3),
+ constructUserPackageIoUsageStats(
+ /*userId=*/12, "com.android.kitchensink",
+ /*writtenBytes=*/constructPerStateBytes(50'000, 40'000, 35'000),
+ /*forgivenWriteBytes=*/constructPerStateBytes(30'000, 30'000, 30'000),
+ /*totalOveruses=*/6)};
+ EXPECT_CALL(*mMockWatchdogServiceHelper, getTodayIoUsageStats(_))
+ .WillOnce(DoAll(SetArgPointee<0>(todayIoUsageStats), Return(Status::ok())));
+
+ EXPECT_CALL(*mMockUidStatsCollector, deltaStats())
+ .WillOnce(Return(
+ constructUidStats({{1001000, {/*fgWrBytes=*/70'000, /*bgWrBytes=*/20'000}},
+ {1112345, {/*fgWrBytes=*/35'000, /*bgWrBytes=*/15'000}}})));
+
+ std::vector<PackageIoOveruseStats> actualIoOveruseStats;
+ EXPECT_CALL(*mMockWatchdogServiceHelper, latestIoOveruseStats(_))
+ .WillOnce(DoAll(SaveArg<0>(&actualIoOveruseStats), Return(Status::ok())));
+
+ time_t currentTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
+ const auto [startTime, durationInSeconds] = calculateStartAndDuration(currentTime);
+
+ ASSERT_RESULT_OK(mIoOveruseMonitor->onPeriodicCollection(currentTime, SystemState::NORMAL_MODE,
+ mMockUidStatsCollector, nullptr));
+
+ std::vector<PackageIoOveruseStats> expectedIoOveruseStats =
+ {constructPackageIoOveruseStats(
+ /*uid*=*/1001000, /*shouldNotify=*/false, /*isKillable=*/false,
+ /*remaining=*/constructPerStateBytes(10'000, 20'000, 100'000),
+ /*written=*/constructPerStateBytes(70'000, 20'000, 0),
+ /*totalOveruses=*/0, startTime, durationInSeconds),
+ constructPackageIoOveruseStats(
+ /*uid*=*/1112345, /*shouldNotify=*/true, /*isKillable=*/true,
+ /*remaining=*/constructPerStateBytes(5'000, 0, 80'000),
+ /*written=*/constructPerStateBytes(135'000, 100'000, 120'000),
+ /*totalOveruses=*/4, startTime, durationInSeconds)};
+ EXPECT_THAT(actualIoOveruseStats, UnorderedElementsAreArray(expectedIoOveruseStats))
+ << "Expected: " << toString(expectedIoOveruseStats)
+ << "\nActual: " << toString(actualIoOveruseStats);
+
+ EXPECT_CALL(*mMockUidStatsCollector, deltaStats())
+ .WillOnce(Return(
+ constructUidStats({{1112345, {/*fgWrBytes=*/70'000, /*bgWrBytes=*/40'000}},
+ {1245678, {/*fgWrBytes=*/30'000, /*bgWrBytes=*/10'000}}})));
+
+ actualIoOveruseStats.clear();
+ EXPECT_CALL(*mMockWatchdogServiceHelper, latestIoOveruseStats(_))
+ .WillOnce(DoAll(SaveArg<0>(&actualIoOveruseStats), Return(Status::ok())));
+
+ ASSERT_RESULT_OK(mIoOveruseMonitor->onPeriodicCollection(currentTime, SystemState::GARAGE_MODE,
+ mMockUidStatsCollector, nullptr));
+
+ expectedIoOveruseStats = {constructPackageIoOveruseStats(
+ /*uid*=*/1112345, /*shouldNotify=*/true, /*isKillable=*/true,
+ /*remaining=*/constructPerStateBytes(70'000, 30'000, 0),
+ /*written=*/constructPerStateBytes(135'000, 100'000, 230'000),
+ /*totalOveruses=*/5, startTime, durationInSeconds),
+ constructPackageIoOveruseStats(
+ /*uid*=*/1245678, /*shouldNotify=*/true, /*isKillable=*/true,
+ /*remaining=*/constructPerStateBytes(10'000, 5'000, 0),
+ /*written=*/constructPerStateBytes(50'000, 40'000, 75'000),
+ /*totalOveruses=*/7, startTime, durationInSeconds)};
+ EXPECT_THAT(actualIoOveruseStats, UnorderedElementsAreArray(expectedIoOveruseStats))
+ << "Expected: " << toString(expectedIoOveruseStats)
+ << "\nActual: " << toString(actualIoOveruseStats);
+}
+
+TEST_F(IoOveruseMonitorTest, TestOnPeriodicCollectionWithErrorFetchingPrevBootStats) {
+ EXPECT_CALL(*mMockWatchdogServiceHelper, getTodayIoUsageStats(_))
+ .WillOnce(Return(Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, "Illegal state")));
+
+ EXPECT_CALL(*mMockUidStatsCollector, deltaStats())
+ .WillOnce(Return(
+ constructUidStats({{1112345, {/*fgWrBytes=*/15'000, /*bgWrBytes=*/15'000}}})));
+
+ time_t currentTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
+ const auto [startTime, durationInSeconds] = calculateStartAndDuration(currentTime);
+
+ ASSERT_RESULT_OK(mIoOveruseMonitor->onPeriodicCollection(currentTime, SystemState::NORMAL_MODE,
+ mMockUidStatsCollector, nullptr));
+
+ std::vector<UserPackageIoUsageStats> todayIoUsageStats = {constructUserPackageIoUsageStats(
+ /*userId=*/11, "com.android.google.package",
+ /*writtenBytes=*/constructPerStateBytes(100'000, 85'000, 120'000),
+ /*forgivenWriteBytes=*/constructPerStateBytes(70'000, 60'000, 100'000),
+ /*totalOveruses=*/3)};
+ EXPECT_CALL(*mMockWatchdogServiceHelper, getTodayIoUsageStats(_))
+ .WillOnce(DoAll(SetArgPointee<0>(todayIoUsageStats), Return(Status::ok())));
+
+ std::vector<PackageIoOveruseStats> actualIoOveruseStats;
+ EXPECT_CALL(*mMockWatchdogServiceHelper, latestIoOveruseStats(_))
+ .WillOnce(DoAll(SaveArg<0>(&actualIoOveruseStats), Return(Status::ok())));
+
+ EXPECT_CALL(*mMockUidStatsCollector, deltaStats())
+ .WillOnce(Return(
+ constructUidStats({{1112345, {/*fgWrBytes=*/20'000, /*bgWrBytes=*/40'000}}})));
+
+ ASSERT_RESULT_OK(mIoOveruseMonitor->onPeriodicCollection(currentTime, SystemState::NORMAL_MODE,
+ mMockUidStatsCollector, nullptr));
+
+ std::vector<PackageIoOveruseStats> expectedIoOveruseStats = {constructPackageIoOveruseStats(
+ /*uid*=*/1112345, /*shouldNotify=*/true, /*isKillable=*/true,
+ /*remaining=*/constructPerStateBytes(5'000, 0, 80'000),
+ /*written=*/constructPerStateBytes(135'000, 140'000, 120'000),
+ /*totalOveruses=*/4, startTime, durationInSeconds)};
+ EXPECT_THAT(actualIoOveruseStats, UnorderedElementsAreArray(expectedIoOveruseStats))
+ << "Expected: " << toString(expectedIoOveruseStats)
+ << "\nActual: " << toString(actualIoOveruseStats);
+}
+
TEST_F(IoOveruseMonitorTest, TestOnPeriodicMonitor) {
IIoOveruseConfigs::IoOveruseAlertThresholdSet alertThresholds =
{toIoOveruseAlertThreshold(
diff --git a/cpp/watchdog/server/tests/MockCarWatchdogServiceForSystem.h b/cpp/watchdog/server/tests/MockCarWatchdogServiceForSystem.h
index d484463a07..07997da839 100644
--- a/cpp/watchdog/server/tests/MockCarWatchdogServiceForSystem.h
+++ b/cpp/watchdog/server/tests/MockCarWatchdogServiceForSystem.h
@@ -53,6 +53,9 @@ public:
(override));
MOCK_METHOD(android::binder::Status, resetResourceOveruseStats,
(const std::vector<std::string>&), (override));
+ MOCK_METHOD(android::binder::Status, getTodayIoUsageStats,
+ (std::vector<android::automotive::watchdog::internal::UserPackageIoUsageStats>*),
+ (override));
private:
android::sp<MockBinder> mBinder;
diff --git a/cpp/watchdog/server/tests/MockWatchdogServiceHelper.h b/cpp/watchdog/server/tests/MockWatchdogServiceHelper.h
index 3d713450d9..171d48c8f1 100644
--- a/cpp/watchdog/server/tests/MockWatchdogServiceHelper.h
+++ b/cpp/watchdog/server/tests/MockWatchdogServiceHelper.h
@@ -61,6 +61,9 @@ public:
(override));
MOCK_METHOD(android::binder::Status, resetResourceOveruseStats,
(const std::vector<std::string>&), (override));
+ MOCK_METHOD(android::binder::Status, getTodayIoUsageStats,
+ (std::vector<android::automotive::watchdog::internal::UserPackageIoUsageStats>*),
+ (override));
MOCK_METHOD(void, terminate, (), (override));
};
diff --git a/cpp/watchdog/server/tests/WatchdogServiceHelperTest.cpp b/cpp/watchdog/server/tests/WatchdogServiceHelperTest.cpp
index de0530095e..1d2f5703bb 100644
--- a/cpp/watchdog/server/tests/WatchdogServiceHelperTest.cpp
+++ b/cpp/watchdog/server/tests/WatchdogServiceHelperTest.cpp
@@ -28,6 +28,8 @@ namespace android {
namespace automotive {
namespace watchdog {
+namespace {
+
namespace aawi = ::android::automotive::watchdog::internal;
using aawi::ApplicationCategoryType;
@@ -36,6 +38,7 @@ using aawi::ICarWatchdogServiceForSystem;
using aawi::PackageInfo;
using aawi::PackageIoOveruseStats;
using aawi::UidType;
+using aawi::UserPackageIoUsageStats;
using ::android::IBinder;
using ::android::RefBase;
using ::android::sp;
@@ -49,6 +52,23 @@ using ::testing::Return;
using ::testing::SetArgPointee;
using ::testing::UnorderedElementsAreArray;
+UserPackageIoUsageStats sampleUserPackageIoUsageStats(userid_t userId,
+ const std::string& packageName) {
+ UserPackageIoUsageStats stats;
+ stats.userId = userId;
+ stats.packageName = packageName;
+ stats.ioUsageStats.writtenBytes.foregroundBytes = 100;
+ stats.ioUsageStats.writtenBytes.backgroundBytes = 200;
+ stats.ioUsageStats.writtenBytes.garageModeBytes = 300;
+ stats.ioUsageStats.forgivenWriteBytes.foregroundBytes = 1100;
+ stats.ioUsageStats.forgivenWriteBytes.backgroundBytes = 1200;
+ stats.ioUsageStats.forgivenWriteBytes.garageModeBytes = 1300;
+ stats.ioUsageStats.totalOveruses = 10;
+ return stats;
+}
+
+} // namespace
+
namespace internal {
class WatchdogServiceHelperPeer : public RefBase {
@@ -439,6 +459,50 @@ TEST_F(WatchdogServiceHelperTest,
"service API returns error";
}
+TEST_F(WatchdogServiceHelperTest, TestGetTodayIoUsageStats) {
+ std::vector<UserPackageIoUsageStats>
+ expectedStats{sampleUserPackageIoUsageStats(10, "vendor.package"),
+ sampleUserPackageIoUsageStats(11, "third_party.package")};
+
+ registerCarWatchdogService();
+
+ EXPECT_CALL(*mMockCarWatchdogServiceForSystem, getTodayIoUsageStats(_))
+ .WillOnce(DoAll(SetArgPointee<0>(expectedStats), Return(Status::ok())));
+
+ std::vector<UserPackageIoUsageStats> actualStats;
+ Status status = mWatchdogServiceHelper->getTodayIoUsageStats(&actualStats);
+
+ ASSERT_TRUE(status.isOk()) << status;
+ EXPECT_THAT(actualStats, UnorderedElementsAreArray(expectedStats));
+}
+
+TEST_F(WatchdogServiceHelperTest,
+ TestErrorOnGetTodayIoUsageStatsWithNoCarWatchdogServiceRegistered) {
+ EXPECT_CALL(*mMockCarWatchdogServiceForSystem, getTodayIoUsageStats(_)).Times(0);
+
+ std::vector<UserPackageIoUsageStats> actualStats;
+ Status status = mWatchdogServiceHelper->getTodayIoUsageStats(&actualStats);
+
+ ASSERT_FALSE(status.isOk()) << "getTodayIoUsageStats should fail when no "
+ "car watchdog service registered with the helper";
+ EXPECT_THAT(actualStats, IsEmpty());
+}
+
+TEST_F(WatchdogServiceHelperTest,
+ TestErrorOnGetTodayIoUsageStatsWithErrorStatusFromCarWatchdogService) {
+ registerCarWatchdogService();
+
+ EXPECT_CALL(*mMockCarWatchdogServiceForSystem, getTodayIoUsageStats(_))
+ .WillOnce(Return(Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, "Illegal state")));
+
+ std::vector<UserPackageIoUsageStats> actualStats;
+ Status status = mWatchdogServiceHelper->getTodayIoUsageStats(&actualStats);
+
+ ASSERT_FALSE(status.isOk()) << "getTodayIoUsageStats should fail when car watchdog "
+ "service API returns error";
+ ASSERT_TRUE(actualStats.empty());
+}
+
} // namespace watchdog
} // namespace automotive
} // namespace android