diff options
author | Lakshman Annadorai <lakshmana@google.com> | 2021-10-08 18:39:10 +0000 |
---|---|---|
committer | Lakshman Annadorai <lakshmana@google.com> | 2021-10-15 02:12:28 +0000 |
commit | 03cbd1f7828332340d15d1eed25ba2cfb4fd35cb (patch) | |
tree | 4f1ae32e542b914468f6103e66667e9245cea557 /cpp/watchdog | |
parent | 2b802eeaee7f374eb10a78dc93ec5291b76156e4 (diff) | |
download | Car-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')
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 |