diff options
author | Lakshman Annadorai <lakshmana@google.com> | 2021-11-18 09:36:19 -0800 |
---|---|---|
committer | Lakshman Annadorai <lakshmana@google.com> | 2021-11-19 21:08:47 +0000 |
commit | a0489c61600e71b8104d4ef2666866a68ed4c6a1 (patch) | |
tree | 2205af03cf60c8942574803663e7950ca9e44791 /cpp/watchdog | |
parent | 345fc0a65a00d1bdcb7131fa1fed590b0f96656e (diff) | |
download | Car-a0489c61600e71b8104d4ef2666866a68ed4c6a1.tar.gz |
Remove stats for deleted user on watchdog daemon side.
- CarService receives user removed broadcast when a user is deleted.
Forward this signal to watchdog daemon, so the daemon can remove the
I/O usage stats cached for the deleted user.
Test: atest CarWatchdogServiceUnitTest libwatchdog_test
Bug: 183413754
Change-Id: Ib3ceead4175e80e307f5044e41bd56b8768273a6
Merged-In: Ib3ceead4175e80e307f5044e41bd56b8768273a6
(cherry-picked from commit 0669122f9e31e34db53d62e19b6d99d02b9554c4)
Diffstat (limited to 'cpp/watchdog')
11 files changed, 198 insertions, 43 deletions
diff --git a/cpp/watchdog/aidl/android/automotive/watchdog/internal/UserState.aidl b/cpp/watchdog/aidl/android/automotive/watchdog/internal/UserState.aidl index 515fb41dac..95461eb966 100644 --- a/cpp/watchdog/aidl/android/automotive/watchdog/internal/UserState.aidl +++ b/cpp/watchdog/aidl/android/automotive/watchdog/internal/UserState.aidl @@ -32,6 +32,11 @@ enum UserState { USER_STATE_STOPPED, /** + * The user is removed. + */ + USER_STATE_REMOVED, + + /** * Number of available user states. */ NUM_USER_STATES, diff --git a/cpp/watchdog/server/src/IoOveruseMonitor.cpp b/cpp/watchdog/server/src/IoOveruseMonitor.cpp index 0ebe0d494e..edf30d8acb 100644 --- a/cpp/watchdog/server/src/IoOveruseMonitor.cpp +++ b/cpp/watchdog/server/src/IoOveruseMonitor.cpp @@ -23,11 +23,11 @@ #include <WatchdogProperties.sysprop.h> #include <android-base/file.h> +#include <android-base/strings.h> #include <android/automotive/watchdog/internal/PackageIdentifier.h> #include <android/automotive/watchdog/internal/UidType.h> #include <binder/IPCThreadState.h> #include <binder/Status.h> -#include <cutils/multiuser.h> #include <log/log.h> #include <processgroup/sched_policy.h> @@ -53,8 +53,10 @@ 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::EndsWith; using ::android::base::Error; using ::android::base::Result; +using ::android::base::StringPrintf; using ::android::base::WriteStringToFd; using ::android::binder::Status; @@ -598,6 +600,7 @@ Result<void> IoOveruseMonitor::resetIoOveruseStats(const std::vector<std::string std::unordered_set<std::string> uniquePackageNames; std::copy(packageNames.begin(), packageNames.end(), std::inserter(uniquePackageNames, uniquePackageNames.end())); + std::unique_lock writeLock(mRwMutex); for (auto& [key, usage] : mUserPackageDailyIoUsageById) { if (uniquePackageNames.find(usage.packageInfo.packageIdentifier.name) != uniquePackageNames.end()) { @@ -607,6 +610,37 @@ Result<void> IoOveruseMonitor::resetIoOveruseStats(const std::vector<std::string return {}; } +void IoOveruseMonitor::removeStatsForUser(userid_t userId) { + std::unique_lock writeLock(mRwMutex); + for (auto it = mUserPackageDailyIoUsageById.begin(); + it != mUserPackageDailyIoUsageById.end();) { + if (multiuser_get_user_id(it->second.packageInfo.packageIdentifier.uid) == userId) { + it = mUserPackageDailyIoUsageById.erase(it); + } else { + ++it; + } + } + // |mPrevBootIoUsageStatsById| keys are constructed using |uniquePackageIdStr| method. Thus, the + // key suffix would contain the userId. The value in this map is |IoUsageStats|, which doesn't + // contain the userId, so this is the only way to delete cached previous boot stats for + // the removed user. + std::string keySuffix = StringPrintf(":%" PRId32, userId); + for (auto it = mPrevBootIoUsageStatsById.begin(); it != mPrevBootIoUsageStatsById.end();) { + if (EndsWith(it->first, keySuffix)) { + it = mPrevBootIoUsageStatsById.erase(it); + } else { + ++it; + } + } + for (auto it = mLatestIoOveruseStats.begin(); it != mLatestIoOveruseStats.end();) { + if (multiuser_get_user_id(it->uid) == userId) { + it = mLatestIoOveruseStats.erase(it); + } else { + ++it; + } + } +} + void IoOveruseMonitor::handleBinderDeath(const wp<IBinder>& who) { std::unique_lock writeLock(mRwMutex); IBinder* binder = who.unsafe_get(); diff --git a/cpp/watchdog/server/src/IoOveruseMonitor.h b/cpp/watchdog/server/src/IoOveruseMonitor.h index 5fa91aae24..d6c261607e 100644 --- a/cpp/watchdog/server/src/IoOveruseMonitor.h +++ b/cpp/watchdog/server/src/IoOveruseMonitor.h @@ -31,6 +31,7 @@ #include <android/automotive/watchdog/internal/IoOveruseConfiguration.h> #include <android/automotive/watchdog/internal/PackageInfo.h> #include <android/automotive/watchdog/internal/PackageIoOveruseStats.h> +#include <cutils/multiuser.h> #include <utils/Mutex.h> #include <time.h> @@ -92,6 +93,9 @@ public: virtual android::base::Result<void> resetIoOveruseStats( const std::vector<std::string>& packageNames) = 0; + + // Removes stats for the given user from the internal cache. + virtual void removeStatsForUser(userid_t userId) = 0; }; class IoOveruseMonitor final : public IIoOveruseMonitor { @@ -161,6 +165,8 @@ public: android::base::Result<void> resetIoOveruseStats( const std::vector<std::string>& packageName) override; + void removeStatsForUser(userid_t userId) override; + protected: android::base::Result<void> init(); diff --git a/cpp/watchdog/server/src/WatchdogInternalHandler.cpp b/cpp/watchdog/server/src/WatchdogInternalHandler.cpp index 2441ccf7f4..d28b322ff3 100644 --- a/cpp/watchdog/server/src/WatchdogInternalHandler.cpp +++ b/cpp/watchdog/server/src/WatchdogInternalHandler.cpp @@ -186,7 +186,7 @@ Status WatchdogInternalHandler::notifySystemStateChange(aawi::StateType type, in return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, StringPrintf("Invalid user state %d", userState)); } - return mWatchdogProcessService->notifyUserStateChange(userId, userState); + return handleUserStateChange(userId, userState); } case aawi::StateType::BOOT_PHASE: { aawi::BootPhase phase = static_cast<aawi::BootPhase>(static_cast<uint32_t>(arg1)); @@ -225,6 +225,29 @@ Status WatchdogInternalHandler::handlePowerCycleChange(PowerCycle powerCycle) { return Status::ok(); } +Status WatchdogInternalHandler::handleUserStateChange(userid_t userId, aawi::UserState userState) { + std::string stateDesc; + switch (userState) { + case aawi::UserState::USER_STATE_STARTED: + stateDesc = "started"; + mWatchdogProcessService->notifyUserStateChange(userId, /*isStarted=*/true); + break; + case aawi::UserState::USER_STATE_STOPPED: + stateDesc = "stopped"; + mWatchdogProcessService->notifyUserStateChange(userId, /*isStarted=*/false); + break; + case aawi::UserState::USER_STATE_REMOVED: + stateDesc = "removed"; + mIoOveruseMonitor->removeStatsForUser(userId); + break; + default: + ALOGW("Unsupported user state: %d", userState); + return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, "Unsupported user state"); + } + ALOGI("Received user state change: user(%" PRId32 ") is %s", userId, stateDesc.c_str()); + return Status::ok(); +} + Status WatchdogInternalHandler::updateResourceOveruseConfigurations( const std::vector<ResourceOveruseConfiguration>& configs) { Status status = checkSystemUser(); diff --git a/cpp/watchdog/server/src/WatchdogInternalHandler.h b/cpp/watchdog/server/src/WatchdogInternalHandler.h index 1000c8e218..6634d5b5c8 100644 --- a/cpp/watchdog/server/src/WatchdogInternalHandler.h +++ b/cpp/watchdog/server/src/WatchdogInternalHandler.h @@ -105,6 +105,9 @@ private: android::binder::Status handlePowerCycleChange( android::automotive::watchdog::internal::PowerCycle powerCycle); + android::binder::Status handleUserStateChange( + userid_t userId, android::automotive::watchdog::internal::UserState userState); + android::sp<WatchdogBinderMediator> mBinderMediator; android::sp<IWatchdogServiceHelper> mWatchdogServiceHelper; android::sp<WatchdogProcessService> mWatchdogProcessService; diff --git a/cpp/watchdog/server/src/WatchdogProcessService.cpp b/cpp/watchdog/server/src/WatchdogProcessService.cpp index 891c6e24b9..3eca5ecc7d 100644 --- a/cpp/watchdog/server/src/WatchdogProcessService.cpp +++ b/cpp/watchdog/server/src/WatchdogProcessService.cpp @@ -289,24 +289,14 @@ void WatchdogProcessService::setEnabled(bool isEnabled) { } } -Status WatchdogProcessService::notifyUserStateChange(userid_t userId, aawi::UserState state) { +void WatchdogProcessService::notifyUserStateChange(userid_t userId, bool isStarted) { std::string buffer; Mutex::Autolock lock(mMutex); - switch (state) { - case aawi::UserState::USER_STATE_STARTED: - mStoppedUserIds.erase(userId); - buffer = StringPrintf("user(%d) is started", userId); - break; - case aawi::UserState::USER_STATE_STOPPED: - mStoppedUserIds.insert(userId); - buffer = StringPrintf("user(%d) is stopped", userId); - break; - default: - ALOGW("Unsupported user state: %d", state); - return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, "Unsupported user state"); + if (isStarted) { + mStoppedUserIds.erase(userId); + } else { + mStoppedUserIds.insert(userId); } - ALOGI("Received user state change: %s", buffer.c_str()); - return Status::ok(); } Result<void> WatchdogProcessService::dump(int fd, const Vector<String16>& /*args*/) { diff --git a/cpp/watchdog/server/src/WatchdogProcessService.h b/cpp/watchdog/server/src/WatchdogProcessService.h index 46d3ef4af6..d66a4207c5 100644 --- a/cpp/watchdog/server/src/WatchdogProcessService.h +++ b/cpp/watchdog/server/src/WatchdogProcessService.h @@ -80,8 +80,7 @@ public: monitor, int32_t pid); virtual void setEnabled(bool isEnabled); - virtual android::binder::Status notifyUserStateChange( - userid_t userId, android::automotive::watchdog::internal::UserState state); + virtual void notifyUserStateChange(userid_t userId, bool isStarted); private: enum ClientType { diff --git a/cpp/watchdog/server/tests/IoOveruseMonitorTest.cpp b/cpp/watchdog/server/tests/IoOveruseMonitorTest.cpp index c1dd4f7d56..752be7438f 100644 --- a/cpp/watchdog/server/tests/IoOveruseMonitorTest.cpp +++ b/cpp/watchdog/server/tests/IoOveruseMonitorTest.cpp @@ -1064,6 +1064,85 @@ TEST_F(IoOveruseMonitorTest, TestFailsUpdateResourceOveruseConfigurations) { ASSERT_FALSE(mIoOveruseMonitor->updateResourceOveruseConfigurations({}).ok()); } +TEST_F(IoOveruseMonitorTest, TestRemoveUser) { + 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), + /*forgiven=*/constructPerStateBytes(0, 0, 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), + /*forgiven=*/constructPerStateBytes(70'000, 90'000, 100'000), + /*totalOveruses=*/4, startTime, durationInSeconds)}; + EXPECT_THAT(actualIoOveruseStats, UnorderedElementsAreArray(expectedIoOveruseStats)) + << "Expected: " << toString(expectedIoOveruseStats) + << "\nActual: " << toString(actualIoOveruseStats); + + mIoOveruseMonitor->removeStatsForUser(/*userId=*/11); + mIoOveruseMonitor->removeStatsForUser(/*userId=*/12); + + 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(0, 0, 110'000), + /*forgiven=*/constructPerStateBytes(0, 0, 100'000), + /*totalOveruses=*/1, startTime, durationInSeconds), + constructPackageIoOveruseStats( + /*uid*=*/1245678, /*shouldNotify=*/true, /*isKillable=*/true, + /*remaining=*/constructPerStateBytes(30'000, 15'000, 0), + /*written=*/constructPerStateBytes(0, 0, 40'000), + /*forgiven=*/constructPerStateBytes(0, 0, 40'000), + /*totalOveruses=*/4, startTime, durationInSeconds)}; + EXPECT_THAT(actualIoOveruseStats, UnorderedElementsAreArray(expectedIoOveruseStats)) + << "Expected: " << toString(expectedIoOveruseStats) + << "\nActual: " << toString(actualIoOveruseStats); +} + } // namespace watchdog } // namespace automotive } // namespace android diff --git a/cpp/watchdog/server/tests/MockIoOveruseMonitor.h b/cpp/watchdog/server/tests/MockIoOveruseMonitor.h index 294276bb48..0e3f4c4842 100644 --- a/cpp/watchdog/server/tests/MockIoOveruseMonitor.h +++ b/cpp/watchdog/server/tests/MockIoOveruseMonitor.h @@ -53,6 +53,7 @@ public: (const, override)); MOCK_METHOD(android::base::Result<void>, resetIoOveruseStats, (const std::vector<std::string>&), (override)); + MOCK_METHOD(void, removeStatsForUser, (userid_t), (override)); }; } // namespace watchdog diff --git a/cpp/watchdog/server/tests/MockWatchdogProcessService.h b/cpp/watchdog/server/tests/MockWatchdogProcessService.h index 44f33770c8..304a2a4f86 100644 --- a/cpp/watchdog/server/tests/MockWatchdogProcessService.h +++ b/cpp/watchdog/server/tests/MockWatchdogProcessService.h @@ -40,42 +40,37 @@ namespace watchdog { class MockWatchdogProcessService : public WatchdogProcessService { public: MockWatchdogProcessService() : WatchdogProcessService(nullptr) {} - MOCK_METHOD(android::base::Result<void>, dump, (int fd, const Vector<android::String16>& args), + MOCK_METHOD(android::base::Result<void>, dump, (int fd, const Vector<android::String16>&), (override)); MOCK_METHOD(android::base::Result<void>, registerWatchdogServiceHelper, - (const android::sp<IWatchdogServiceHelper>& helper), (override)); + (const android::sp<IWatchdogServiceHelper>&), (override)); MOCK_METHOD(android::binder::Status, registerClient, - (const sp<ICarWatchdogClient>& client, TimeoutLength timeout), (override)); - MOCK_METHOD(android::binder::Status, unregisterClient, (const sp<ICarWatchdogClient>& client), + (const sp<ICarWatchdogClient>&, TimeoutLength), (override)); + MOCK_METHOD(android::binder::Status, unregisterClient, (const sp<ICarWatchdogClient>&), (override)); - MOCK_METHOD(android::binder::Status, registerCarWatchdogService, - (const android::sp<IBinder>& binder), (override)); - MOCK_METHOD(void, unregisterCarWatchdogService, (const android::sp<IBinder>& binder), + MOCK_METHOD(android::binder::Status, registerCarWatchdogService, (const android::sp<IBinder>&), (override)); + MOCK_METHOD(void, unregisterCarWatchdogService, (const android::sp<IBinder>&), (override)); MOCK_METHOD(android::binder::Status, registerMonitor, - (const sp<android::automotive::watchdog::internal::ICarWatchdogMonitor>& monitor), + (const sp<android::automotive::watchdog::internal::ICarWatchdogMonitor>&), (override)); MOCK_METHOD(android::binder::Status, unregisterMonitor, - (const sp<android::automotive::watchdog::internal::ICarWatchdogMonitor>& monitor), + (const sp<android::automotive::watchdog::internal::ICarWatchdogMonitor>&), + (override)); + MOCK_METHOD(android::binder::Status, tellClientAlive, (const sp<ICarWatchdogClient>&, int32_t), (override)); - MOCK_METHOD(android::binder::Status, tellClientAlive, - (const sp<ICarWatchdogClient>& client, int32_t sessionId), (override)); MOCK_METHOD(android::binder::Status, tellCarWatchdogServiceAlive, (const android::sp< - android::automotive::watchdog::internal::ICarWatchdogServiceForSystem>& - service, - const std::vector<int32_t>& clientsNotResponding, int32_t sessionId), + android::automotive::watchdog::internal::ICarWatchdogServiceForSystem>&, + const std::vector<int32_t>&, int32_t), (override)); MOCK_METHOD(android::binder::Status, tellDumpFinished, - (const android::sp<android::automotive::watchdog::internal::ICarWatchdogMonitor>& - monitor, - int32_t pid), + (const android::sp<android::automotive::watchdog::internal::ICarWatchdogMonitor>&, + int32_t), (override)); MOCK_METHOD(void, setEnabled, (bool), (override)); - MOCK_METHOD(android::binder::Status, notifyUserStateChange, - (userid_t userId, android::automotive::watchdog::internal::UserState state), - (override)); + MOCK_METHOD(void, notifyUserStateChange, (userid_t, bool), (override)); }; } // namespace watchdog diff --git a/cpp/watchdog/server/tests/WatchdogInternalHandlerTest.cpp b/cpp/watchdog/server/tests/WatchdogInternalHandlerTest.cpp index a5abbc4381..3d95bc687a 100644 --- a/cpp/watchdog/server/tests/WatchdogInternalHandlerTest.cpp +++ b/cpp/watchdog/server/tests/WatchdogInternalHandlerTest.cpp @@ -362,12 +362,21 @@ TEST_F(WatchdogInternalHandlerTest, TestNotifyGarageModeOff) { ASSERT_TRUE(status.isOk()) << status; } -TEST_F(WatchdogInternalHandlerTest, TestNotifyUserStateChange) { +TEST_F(WatchdogInternalHandlerTest, TestNotifyUserStateChangeWithStartedUser) { setSystemCallingUid(); aawi::StateType type = aawi::StateType::USER_STATE; - EXPECT_CALL(*mMockWatchdogProcessService, - notifyUserStateChange(234567, aawi::UserState::USER_STATE_STOPPED)) - .WillOnce(Return(Status::ok())); + EXPECT_CALL(*mMockWatchdogProcessService, notifyUserStateChange(234567, /*isStarted=*/true)); + Status status = mWatchdogInternalHandler + ->notifySystemStateChange(type, 234567, + static_cast<int32_t>( + aawi::UserState::USER_STATE_STARTED)); + ASSERT_TRUE(status.isOk()) << status; +} + +TEST_F(WatchdogInternalHandlerTest, TestNotifyUserStateChangeWithStoppedUser) { + setSystemCallingUid(); + aawi::StateType type = aawi::StateType::USER_STATE; + EXPECT_CALL(*mMockWatchdogProcessService, notifyUserStateChange(234567, /*isStarted=*/false)); Status status = mWatchdogInternalHandler ->notifySystemStateChange(type, 234567, static_cast<int32_t>( @@ -375,6 +384,17 @@ TEST_F(WatchdogInternalHandlerTest, TestNotifyUserStateChange) { ASSERT_TRUE(status.isOk()) << status; } +TEST_F(WatchdogInternalHandlerTest, TestNotifyUserStateChangeWithRemovedUser) { + setSystemCallingUid(); + aawi::StateType type = aawi::StateType::USER_STATE; + EXPECT_CALL(*mMockIoOveruseMonitor, removeStatsForUser(/*userId=*/234567)); + Status status = mWatchdogInternalHandler + ->notifySystemStateChange(type, 234567, + static_cast<int32_t>( + aawi::UserState::USER_STATE_REMOVED)); + ASSERT_TRUE(status.isOk()) << status; +} + TEST_F(WatchdogInternalHandlerTest, TestErrorOnNotifyUserStateChangeWithInvalidArgs) { EXPECT_CALL(*mMockWatchdogProcessService, notifyUserStateChange(_, _)).Times(0); aawi::StateType type = aawi::StateType::USER_STATE; |