/* * Copyright 2020 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. */ #include "MockAIBinderDeathRegistrationWrapper.h" #include "MockCarWatchdogMonitor.h" #include "MockCarWatchdogServiceForSystem.h" #include "MockHidlServiceManager.h" #include "MockPackageInfoResolver.h" #include "MockVhalClient.h" #include "MockWatchdogServiceHelper.h" #include "PackageInfoResolver.h" #include "WatchdogProcessService.h" #include "WatchdogServiceHelper.h" #include #include #include #include #include #include #include // NOLINT(build/c++11) #include #include #include namespace android { namespace automotive { namespace watchdog { using ::aidl::android::automotive::watchdog::ICarWatchdogClient; using ::aidl::android::automotive::watchdog::ICarWatchdogClientDefault; using ::aidl::android::automotive::watchdog::TimeoutLength; using ::aidl::android::automotive::watchdog::internal::BnCarWatchdogMonitor; using ::aidl::android::automotive::watchdog::internal::GarageMode; using ::aidl::android::automotive::watchdog::internal::ICarWatchdogMonitor; using ::aidl::android::automotive::watchdog::internal::ICarWatchdogMonitorDefault; using ::aidl::android::automotive::watchdog::internal::ProcessIdentifier; using ::aidl::android::hardware::automotive::vehicle::IVehicleCallback; using ::aidl::android::hardware::automotive::vehicle::RawPropValues; using ::aidl::android::hardware::automotive::vehicle::SubscribeOptions; using ::aidl::android::hardware::automotive::vehicle::VehicleProperty; using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue; using ::aidl::android::hardware::automotive::vehicle::VehiclePropValues; using ::android::IBinder; using ::android::Looper; using ::android::sp; using ::android::base::Error; using ::android::car::feature::car_watchdog_anr_metrics; using ::android::frameworks::automotive::vhal::ClientStatusError; using ::android::frameworks::automotive::vhal::ErrorCode; using ::android::frameworks::automotive::vhal::IHalPropConfig; using ::android::frameworks::automotive::vhal::IVhalClient; using ::android::frameworks::automotive::vhal::VhalClientError; using ::android::frameworks::automotive::vhal::VhalClientResult; using ::android::hidl::base::V1_0::DebugInfo; using ::android::hidl::manager::V1_0::IServiceManager; using ::android::util::ProtoReader; using ::ndk::ScopedAStatus; using ::ndk::SharedRefBase; using ::ndk::SpAIBinder; using ::testing::_; using ::testing::ByMove; using ::testing::Eq; using ::testing::Field; using ::testing::Invoke; using ::testing::Matcher; using ::testing::NiceMock; using ::testing::Return; using ::testing::SizeIs; using ::testing::UnorderedElementsAreArray; namespace { constexpr std::chrono::milliseconds kMaxWaitForLooperExecutionMillis = 5s; constexpr std::chrono::nanoseconds kTestVhalPidCachingRetryDelayNs = 20ms; constexpr char kTestLooperThreadName[] = "WdProcSvcTest"; constexpr char kTestPidComm[] = "test_pid_comm"; constexpr const int32_t kTestAidlVhalPid = 564269; constexpr const int32_t kTestAidlVhalUid = 100124025; constexpr const int32_t kTestAidlVhalTgid = 564269; constexpr const int32_t kTestPidStartTime = 12356; constexpr const int32_t kMaxVhalPidCachingAttempts = 2; constexpr std::chrono::milliseconds kTestVhalHealthCheckIntervalMillis = 200ms; constexpr std::chrono::milliseconds kTestVhalHealthCheckDelayMillis = 100ms; constexpr const int32_t kTestAidlClientUid = 100124036; enum TestMessage { SYNC_LOOPER_MARKER, ON_AIDL_VHAL_PID, UPDATE_VHAL_HEARTBEAT, }; ProcessIdentifier constructProcessIdentifier(pid_t pid, uid_t uid, std::string processName, int64_t startTimeMillis) { ProcessIdentifier processIdentifier; processIdentifier.pid = pid; processIdentifier.startTimeMillis = startTimeMillis; processIdentifier.uid = uid; processIdentifier.processName = processName; return processIdentifier; } MATCHER_P(ProcessIdentifierEq, expected, "") { return ExplainMatchResult(AllOf(Field("pid", &ProcessIdentifier::pid, Eq(expected.pid)), Field("startTimeMillis", &ProcessIdentifier::startTimeMillis, Eq(expected.startTimeMillis)), Field("processName", &ProcessIdentifier::processName, Eq(expected.processName)), Field("uid", &ProcessIdentifier::uid, Eq(expected.uid))), arg, result_listener); } std::vector> constructProcessIdentifierMatchers( const std::vector& processIdentifiers) { std::vector> processIdentifierMatchers; processIdentifierMatchers.reserve(processIdentifiers.size()); for (const auto& processIdentifier : processIdentifiers) { processIdentifierMatchers.push_back(ProcessIdentifierEq(processIdentifier)); } return processIdentifierMatchers; } MATCHER_P(ClientsNotRespondingInfoEq, expected, "") { return ExplainMatchResult(AllOf(Field("processIdentifiers", &ClientsNotRespondingInfo::processIdentifiers, UnorderedElementsAreArray( constructProcessIdentifierMatchers( expected.processIdentifiers))), Field("garageMode", &ClientsNotRespondingInfo::garageMode, Eq(expected.garageMode))), arg, result_listener); } } // namespace namespace internal { class WatchdogProcessServicePeer final { public: explicit WatchdogProcessServicePeer( const sp& watchdogProcessService, const std::shared_ptr& packageInfoResolver) : mWatchdogProcessService(watchdogProcessService) { Mutex::Autolock lock(mWatchdogProcessService->mMutex); mWatchdogProcessService->mPackageInfoResolver = packageInfoResolver; } void expectVhalProcessIdentifier(const Matcher matcher) { Mutex::Autolock lock(mWatchdogProcessService->mMutex); EXPECT_TRUE(mWatchdogProcessService->mVhalProcessIdentifier.has_value()); EXPECT_THAT(mWatchdogProcessService->mVhalProcessIdentifier.value(), matcher); } void expectNoVhalProcessIdentifier() { EXPECT_FALSE(mWatchdogProcessService->mVhalProcessIdentifier.has_value()); } void setWatchdogProcessServiceState( bool isEnabled, std::shared_ptr monitor, std::chrono::nanoseconds overriddenClientHealthCheckWindowNs, std::unordered_set stoppedUserIds, const ProcessIdentifier& processIdentifier) { Mutex::Autolock lock(mWatchdogProcessService->mMutex); mWatchdogProcessService->mIsEnabled = isEnabled; mWatchdogProcessService->mMonitor = monitor; mWatchdogProcessService->mOverriddenClientHealthCheckWindowNs = overriddenClientHealthCheckWindowNs; mWatchdogProcessService->mStoppedUserIds = stoppedUserIds; mWatchdogProcessService->mVhalProcessIdentifier = processIdentifier; WatchdogProcessService::ClientInfoMap clientInfoMap; WatchdogProcessService::ClientInfo clientInfo( /*client=*/nullptr, /*pid=*/1, kTestAidlClientUid, /*processName=*/"", /*startTimeMillis=*/1000, WatchdogProcessService(nullptr)); clientInfo.packageName = "shell"; clientInfoMap.insert({100, clientInfo}); mWatchdogProcessService->mClientsByTimeout.clear(); mWatchdogProcessService->mClientsByTimeout.insert( {TimeoutLength::TIMEOUT_CRITICAL, clientInfoMap}); } void clearClientsByTimeout() { mWatchdogProcessService->mClientsByTimeout.clear(); } base::Result dumpAndKillAllProcesses( const std::vector& processesNotResponding, bool reportToVhal) { return mWatchdogProcessService->dumpAndKillAllProcesses(processesNotResponding, reportToVhal); } bool hasClientInfoWithPackageName(TimeoutLength timeoutLength, std::string packageName) { auto clientInfoMap = mWatchdogProcessService->mClientsByTimeout[timeoutLength]; for (const auto& [_, clientInfo] : clientInfoMap) { if (clientInfo.packageName == packageName) { return true; } } return false; } bool hasClientInfoWithProcessName(TimeoutLength timeoutLength, std::string processName) { auto clientInfoMap = mWatchdogProcessService->mClientsByTimeout[timeoutLength]; for (const auto& [_, clientInfo] : clientInfoMap) { if (clientInfo.kProcessName == processName) { return true; } } return false; } private: sp mWatchdogProcessService; }; } // namespace internal class WatchdogProcessServiceTest : public ::testing::Test { public: WatchdogProcessServiceTest() : mMockVhalClient(nullptr), mMockHidlServiceManager(nullptr), kTryCreateVhalClientFunc([this]() { return mMockVhalClient; }), kTryGetHidlServiceManagerFunc([this]() { return mMockHidlServiceManager; }), kGetPidStatForPidFunc([](pid_t) { return PidStat{ .startTimeMillis = kTestPidStartTime, .comm = kTestPidComm, }; }), kGetUidForPidFunc([](pid_t) { return kTestAidlVhalUid; }), mVhalHeartbeatUpdateIntervalMillis(kTestVhalHealthCheckIntervalMillis) {} protected: void SetUp() override { mMessageHandler = sp::make(this); mMockVehicle = SharedRefBase::make>(); mMockVhalClient = std::make_shared>(mMockVehicle); mMockHidlServiceManager = sp::make(); mMockDeathRegistrationWrapper = sp::make(); mSupportedVehicleProperties = {VehicleProperty::VHAL_HEARTBEAT}; mNotSupportedVehicleProperties = {VehicleProperty::WATCHDOG_ALIVE, VehicleProperty::WATCHDOG_TERMINATED_PROCESS}; mMockPackageInfoResolver = std::make_shared(); mMockWatchdogMonitor = SharedRefBase::make(); ON_CALL(*mMockVehicle, subscribe(_, _, _)) .WillByDefault([this](const std::shared_ptr& callback, const std::vector&, int32_t) { { std::lock_guard lock(mMutex); mSubscribedCallback = callback; } mLooperCondition.notify_all(); return ScopedAStatus::ok(); }); startService(); } void TearDown() override { terminateService(); mMockDeathRegistrationWrapper.clear(); mMockHidlServiceManager.clear(); mMockVhalClient.reset(); mMockVehicle.reset(); mMessageHandler.clear(); mMockPackageInfoResolver.reset(); } void startService() { prepareLooper(); mWatchdogProcessService = sp::make(kTryCreateVhalClientFunc, kTryGetHidlServiceManagerFunc, kGetPidStatForPidFunc, kGetUidForPidFunc, kTestVhalPidCachingRetryDelayNs, mHandlerLooper, mMockDeathRegistrationWrapper, kTestVhalHealthCheckIntervalMillis, kTestVhalHealthCheckDelayMillis); mWatchdogProcessServicePeer = std::make_unique(mWatchdogProcessService, mMockPackageInfoResolver); expectGetPropConfigs(mSupportedVehicleProperties, mNotSupportedVehicleProperties); mWatchdogProcessService->start(); // Sync with the looper before proceeding to ensure that all startup looper messages are // processed before testing the service. ASSERT_TRUE(syncLooper()) << "Looper not finish handling pending tasks before timeout, probably stuck"; } void terminateService() { wakeAndJoinLooper(); mWatchdogProcessServicePeer.reset(); mWatchdogProcessService->terminate(); mWatchdogProcessService.clear(); mHandlerLooper.clear(); } bool waitForSubscribedCallbackSet(std::chrono::milliseconds timeoutMillis) { std::unique_lock lock(mMutex); return mLooperCondition.wait_for(lock, timeoutMillis, [this] { return mSubscribedCallback != nullptr; }); } void scheduleVhalHeartBeatUpdate(std::chrono::milliseconds delayMillis = 0ms) { mHandlerLooper->sendMessageDelayed(std::chrono::nanoseconds(delayMillis).count(), mMessageHandler, Message(TestMessage::UPDATE_VHAL_HEARTBEAT)); } void setVhalHeartbeatUpdateInterval( std::chrono::milliseconds vhalHeartbeatUpdateIntervalMillis) { mVhalHeartbeatUpdateIntervalMillis = vhalHeartbeatUpdateIntervalMillis; } void expectLinkToDeath(AIBinder* aiBinder, ScopedAStatus expectedStatus) { EXPECT_CALL(*mMockDeathRegistrationWrapper, linkToDeath(Eq(aiBinder), _, static_cast(aiBinder))) .WillOnce(Return(ByMove(std::move(expectedStatus)))); } void expectUnlinkToDeath(AIBinder* aiBinder, ScopedAStatus expectedStatus) { EXPECT_CALL(*mMockDeathRegistrationWrapper, unlinkToDeath(Eq(aiBinder), _, static_cast(aiBinder))) .WillOnce(Return(ByMove(std::move(expectedStatus)))); } void expectNoUnlinkToDeath(AIBinder* aiBinder) { EXPECT_CALL(*mMockDeathRegistrationWrapper, unlinkToDeath(Eq(aiBinder), _, static_cast(aiBinder))) .Times(0); } void expectGetPropConfigs(const std::vector& supportedProperties, const std::vector& notSupportedProperties) { for (const auto& propId : supportedProperties) { EXPECT_CALL(*mMockVhalClient, getPropConfigs(std::vector{static_cast(propId)})) .WillOnce([]() { return std::vector>(); }); } for (const auto& propId : notSupportedProperties) { EXPECT_CALL(*mMockVhalClient, getPropConfigs(std::vector{static_cast(propId)})) .WillOnce( []() -> VhalClientResult>> { return Error(ErrorCode::NOT_AVAILABLE_FROM_VHAL) << "Not supported"; }); } } // Expect the requestAidlVhalPid call from the implementation on registering CarWatchdogService // and mimic CarWatchdogService response by posting the onAidlVhalPidFetched call on the looper. void expectRequestAidlVhalPidAndRespond( const sp& mockServiceHelper) { EXPECT_CALL(*mockServiceHelper, requestAidlVhalPid()).WillOnce([&]() { mHandlerLooper->sendMessageDelayed(kTestVhalPidCachingRetryDelayNs.count() / 2, mMessageHandler, Message(TestMessage::ON_AIDL_VHAL_PID)); return ScopedAStatus::ok(); }); } // Wait for ON_AIDL_VHAL_PID message is handled. This is only supposed to be called once. // If you need to wait for another ON_AIDL_VHAL_PID to be handled, mOnAidlVhalPidHandled must // be reset to false. bool waitForOnAidlVhalPidHandled(std::chrono::milliseconds timeoutMillis) { std::unique_lock lock(mMutex); return mLooperCondition.wait_for(lock, timeoutMillis, [this] { return mOnAidlVhalPidHandled; }); } // Finishes all the posted tasks that are supposed to run inside the handler. bool syncLooper(std::chrono::nanoseconds delay = 0ns) { // Acquire the lock before sending message to avoid any race condition. std::unique_lock lock(mMutex); mLooperSynced = false; mHandlerLooper->sendMessageDelayed(delay.count(), mMessageHandler, Message(TestMessage::SYNC_LOOPER_MARKER)); return mLooperCondition .wait_for(lock, kMaxWaitForLooperExecutionMillis + std::chrono::duration_cast(delay), [this] { return mLooperSynced; }); } bool waitUntilVhalPidCachingAttemptsExhausted() { return syncLooper((kMaxVhalPidCachingAttempts + 1) * kTestVhalPidCachingRetryDelayNs); } std::string toString(util::ProtoOutputStream* proto) { std::string content; content.reserve(proto->size()); sp reader = proto->data(); while (reader->hasNext()) { content.push_back(reader->next()); } return content; } void setupMockCarServiceAndWaitForAidlVhalPidFetched(); sp mWatchdogProcessService; std::unique_ptr mWatchdogProcessServicePeer; std::shared_ptr> mMockVhalClient; std::shared_ptr> mMockVehicle; sp mMockHidlServiceManager; sp mMockDeathRegistrationWrapper; std::vector mSupportedVehicleProperties; std::vector mNotSupportedVehicleProperties; std::shared_ptr mMockPackageInfoResolver; std::shared_ptr mMockWatchdogMonitor; private: class MessageHandlerImpl : public android::MessageHandler { public: explicit MessageHandlerImpl(WatchdogProcessServiceTest* test) : mTest(test) {} void handleMessage(const Message& message) override { switch (message.what) { case static_cast(TestMessage::SYNC_LOOPER_MARKER): mTest->handleSyncLooperMarker(); break; case static_cast(TestMessage::ON_AIDL_VHAL_PID): mTest->handleOnAidlVhalPid(); break; case static_cast(TestMessage::UPDATE_VHAL_HEARTBEAT): mTest->updateVhalHeartBeat(); break; default: ALOGE("Unknown TestMessage: %d", message.what); return; } std::lock_guard lock(mTest->mMutex); mTest->mLooperCondition.notify_all(); } private: WatchdogProcessServiceTest* mTest; }; // Looper runs on the calling thread when it is polled for messages with the poll* calls. // The poll* calls are blocking, so they must be executed on a separate thread. void prepareLooper() { mHandlerLooper = sp::make(/*allowNonCallbacks=*/false); mHandlerLooperThread = std::thread([this]() { Looper::setForThread(mHandlerLooper); if (int result = pthread_setname_np(pthread_self(), kTestLooperThreadName); result != 0) { ALOGE("Failed to set test looper thread name: %s", strerror(result)); } mShouldTerminateLooper.store(false); while (!mShouldTerminateLooper.load()) { mHandlerLooper->pollAll(/*timeoutMillis=*/-1); } }); } void wakeAndJoinLooper() { // Sync with the looper to make sure all messages for the current time slot are processed // before terminating the looper. This will help satisfy any pending EXPECT_CALLs. syncLooper(); mShouldTerminateLooper.store(true); mHandlerLooper->wake(); if (mHandlerLooperThread.joinable()) { mHandlerLooperThread.join(); } } void updateVhalHeartBeat() { std::shared_ptr callback; { std::lock_guard lock(mMutex); callback = mSubscribedCallback; } int64_t now = uptimeNanos(); callback->onPropertyEvent( VehiclePropValues{ .payloads = {VehiclePropValue{ .timestamp = now, .prop = static_cast(VehicleProperty::VHAL_HEARTBEAT), .areaId = 0, .value = RawPropValues{ .int64Values = {now}, }, }}, }, /*sharedMemoryCount=*/0); if (mShouldTerminateLooper.load()) { return; } // Schedule the next VHAL heartbeat update unless the test is ending. scheduleVhalHeartBeatUpdate(mVhalHeartbeatUpdateIntervalMillis); } void handleOnAidlVhalPid() { mWatchdogProcessService->onAidlVhalPidFetched(kTestAidlVhalPid); { std::lock_guard lock(mMutex); mOnAidlVhalPidHandled = true; } mLooperCondition.notify_all(); } void handleSyncLooperMarker() { { std::lock_guard lock(mMutex); mLooperSynced = true; } mLooperCondition.notify_all(); } const std::function()> kTryCreateVhalClientFunc; const std::function()> kTryGetHidlServiceManagerFunc; const std::function kGetPidStatForPidFunc; const std::function kGetUidForPidFunc; sp mHandlerLooper; sp mMessageHandler; std::thread mHandlerLooperThread; mutable std::mutex mMutex; std::atomic mShouldTerminateLooper; std::atomic mVhalHeartbeatUpdateIntervalMillis; std::condition_variable mLooperCondition; // The following are variables that notified by mLooperCondition; std::shared_ptr mSubscribedCallback GUARDED_BY(mMutex); bool mOnAidlVhalPidHandled GUARDED_BY(mMutex) = false; bool mLooperSynced GUARDED_BY(mMutex) = false; }; void WatchdogProcessServiceTest::setupMockCarServiceAndWaitForAidlVhalPidFetched() { sp mockServiceHelper = sp::make(); std::shared_ptr mockService = SharedRefBase::make(); const auto binder = mockService->asBinder(); ON_CALL(*mMockPackageInfoResolver, asyncFetchPackageNamesForUids(_, _)) .WillByDefault([&](const std::vector& uids, const std::function)>& callback) { callback({{uids[0], "shell"}}); }); // For mock services, if they are checked, they will respond alive to prevent being killed. ON_CALL(*mockService, checkIfAlive).WillByDefault([]() { return ScopedAStatus::ok(); }); ON_CALL(*mockServiceHelper, checkIfAlive).WillByDefault([]() { return ScopedAStatus::ok(); }); expectRequestAidlVhalPidAndRespond(mockServiceHelper); auto status = mWatchdogProcessService->registerCarWatchdogService(binder, mockServiceHelper); ASSERT_TRUE(status.isOk()) << status.getMessage(); ASSERT_TRUE(waitForOnAidlVhalPidHandled(kMaxWaitForLooperExecutionMillis)) << "ON_AIDL_VHAL_PID is not handled before timeout"; ASSERT_NO_FATAL_FAILURE(mWatchdogProcessServicePeer->expectVhalProcessIdentifier( ProcessIdentifierEq(constructProcessIdentifier(kTestAidlVhalPid, kTestAidlVhalUid, kTestPidComm, kTestPidStartTime)))); } TEST_F(WatchdogProcessServiceTest, TestTerminate) { std::vector propIds = {static_cast(VehicleProperty::VHAL_HEARTBEAT)}; EXPECT_CALL(*mMockVhalClient, removeOnBinderDiedCallback(_)).Times(1); EXPECT_CALL(*mMockVehicle, unsubscribe(_, propIds)) .WillOnce(Return(ByMove(ScopedAStatus::ok()))); mWatchdogProcessService->terminate(); // TODO(b/217405065): Verify looper removes all MSG_VHAL_HEALTH_CHECK messages. } // TODO(b/217405065): Add test to verify the handleVhalDeath method. TEST_F(WatchdogProcessServiceTest, TestRegisterClient) { std::shared_ptr client = SharedRefBase::make(); expectLinkToDeath(client->asBinder().get(), ScopedAStatus::ok()); auto status = mWatchdogProcessService->registerClient(client, TimeoutLength::TIMEOUT_CRITICAL); ASSERT_TRUE(status.isOk()) << status.getMessage(); status = mWatchdogProcessService->registerClient(client, TimeoutLength::TIMEOUT_CRITICAL); ASSERT_TRUE(status.isOk()) << status.getMessage(); } TEST_F(WatchdogProcessServiceTest, TestUnregisterClient) { std::shared_ptr client = SharedRefBase::make(); AIBinder* aiBinder = client->asBinder().get(); expectLinkToDeath(aiBinder, ScopedAStatus::ok()); auto status = mWatchdogProcessService->registerClient(client, TimeoutLength::TIMEOUT_CRITICAL); ASSERT_TRUE(status.isOk()) << status.getMessage(); expectUnlinkToDeath(aiBinder, ScopedAStatus::ok()); status = mWatchdogProcessService->unregisterClient(client); ASSERT_TRUE(status.isOk()) << status.getMessage(); ASSERT_FALSE(mWatchdogProcessService->unregisterClient(client).isOk()) << "Unregistering an unregistered client should return an error"; } TEST_F(WatchdogProcessServiceTest, TestErrorOnRegisterClientWithDeadBinder) { std::shared_ptr client = SharedRefBase::make(); expectLinkToDeath(client->asBinder().get(), ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED)); ASSERT_FALSE( mWatchdogProcessService->registerClient(client, TimeoutLength::TIMEOUT_CRITICAL).isOk()) << "When linkToDeath fails, registerClient should return an error"; } TEST_F(WatchdogProcessServiceTest, TestHandleClientBinderDeath) { std::shared_ptr client = SharedRefBase::make(); AIBinder* aiBinder = client->asBinder().get(); expectLinkToDeath(aiBinder, ScopedAStatus::ok()); auto status = mWatchdogProcessService->registerClient(client, TimeoutLength::TIMEOUT_CRITICAL); ASSERT_TRUE(status.isOk()) << status.getMessage(); mWatchdogProcessService->handleBinderDeath(static_cast(aiBinder)); expectNoUnlinkToDeath(aiBinder); ASSERT_FALSE(mWatchdogProcessService->unregisterClient(client).isOk()) << "Unregistering a dead client should return an error"; } TEST_F(WatchdogProcessServiceTest, TestRegisterCarWatchdogService) { sp mockServiceHelper = sp::make(); std::shared_ptr mockService = SharedRefBase::make(); const auto binder = mockService->asBinder(); EXPECT_CALL(*mockServiceHelper, requestAidlVhalPid()) .WillOnce(Return(ByMove(ScopedAStatus::ok()))); auto status = mWatchdogProcessService->registerCarWatchdogService(binder, mockServiceHelper); ASSERT_TRUE(status.isOk()) << status.getMessage(); // The implementation posts message on the looper to cache VHAL pid when registering // the car watchdog service. So, sync with the looper to ensure the above requestAidlVhalPid // EXPECT_CALL is satisfied. ASSERT_TRUE(syncLooper()) << "Looper not finish handling pending tasks before timeout, probably stuck"; // No new request to fetch AIDL VHAL pid should be sent on duplicate registration. EXPECT_CALL(*mockServiceHelper, requestAidlVhalPid()).Times(0); status = mWatchdogProcessService->registerCarWatchdogService(binder, mockServiceHelper); ASSERT_TRUE(status.isOk()) << status.getMessage(); } TEST_F(WatchdogProcessServiceTest, TestErrorOnRegisterCarWatchdogServiceWithNullWatchdogServiceHelper) { std::shared_ptr mockService = SharedRefBase::make(); const auto binder = mockService->asBinder(); ASSERT_FALSE(mWatchdogProcessService->registerCarWatchdogService(binder, nullptr).isOk()) << "Registering car watchdog service should fail when watchdog service helper is null"; } TEST_F(WatchdogProcessServiceTest, TestRegisterMonitor) { std::shared_ptr monitorOne = SharedRefBase::make(); expectLinkToDeath(monitorOne->asBinder().get(), ScopedAStatus::ok()); auto status = mWatchdogProcessService->registerMonitor(monitorOne); ASSERT_TRUE(status.isOk()) << status.getMessage(); status = mWatchdogProcessService->registerMonitor(monitorOne); ASSERT_TRUE(status.isOk()) << status.getMessage(); std::shared_ptr monitorTwo = SharedRefBase::make(); status = mWatchdogProcessService->registerMonitor(monitorTwo); ASSERT_TRUE(status.isOk()) << status.getMessage(); } TEST_F(WatchdogProcessServiceTest, TestErrorOnRegisterMonitorWithDeadBinder) { std::shared_ptr monitor = SharedRefBase::make(); expectLinkToDeath(monitor->asBinder().get(), ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED)); ASSERT_FALSE(mWatchdogProcessService->registerMonitor(monitor).isOk()) << "When linkToDeath fails, registerMonitor should return an error"; } TEST_F(WatchdogProcessServiceTest, TestUnregisterMonitor) { std::shared_ptr monitor = SharedRefBase::make(); AIBinder* aiBinder = monitor->asBinder().get(); expectLinkToDeath(aiBinder, ScopedAStatus::ok()); auto status = mWatchdogProcessService->registerMonitor(monitor); ASSERT_TRUE(status.isOk()) << status.getMessage(); expectUnlinkToDeath(aiBinder, ScopedAStatus::ok()); status = mWatchdogProcessService->unregisterMonitor(monitor); ASSERT_TRUE(status.isOk()) << status.getMessage(); ASSERT_FALSE(mWatchdogProcessService->unregisterMonitor(monitor).isOk()) << "Unregistering an unregistered monitor should return an error"; } TEST_F(WatchdogProcessServiceTest, TestHandleMonitorBinderDeath) { std::shared_ptr monitor = SharedRefBase::make(); AIBinder* aiBinder = monitor->asBinder().get(); expectLinkToDeath(aiBinder, ScopedAStatus::ok()); auto status = mWatchdogProcessService->registerMonitor(monitor); ASSERT_TRUE(status.isOk()) << status.getMessage(); mWatchdogProcessService->handleBinderDeath(static_cast(aiBinder)); expectNoUnlinkToDeath(aiBinder); ASSERT_FALSE(mWatchdogProcessService->unregisterMonitor(monitor).isOk()) << "Unregistering a dead monitor should return an error"; } TEST_F(WatchdogProcessServiceTest, TestTellClientAlive) { std::shared_ptr client = SharedRefBase::make(); expectLinkToDeath(client->asBinder().get(), ScopedAStatus::ok()); mWatchdogProcessService->registerClient(client, TimeoutLength::TIMEOUT_CRITICAL); ASSERT_FALSE(mWatchdogProcessService->tellClientAlive(client, 1234).isOk()) << "tellClientAlive not synced with checkIfAlive should return an error"; } TEST_F(WatchdogProcessServiceTest, TestTellCarWatchdogServiceAlive) { std::shared_ptr mockService = SharedRefBase::make(); std::vector processIdentifiers; processIdentifiers.push_back(constructProcessIdentifier(/*pid=*/111, /*uid=*/1, /*processName=*/"process1", /*startTimeMillis=*/0)); processIdentifiers.push_back(constructProcessIdentifier(/*pid=*/222, /*uid=*/2, /*processName=*/"process2", /*startTimeMillis=*/0)); ASSERT_FALSE(mWatchdogProcessService ->tellCarWatchdogServiceAlive(mockService, processIdentifiers, 1234) .isOk()) << "tellCarWatchdogServiceAlive not synced with checkIfAlive should return an error"; } TEST_F(WatchdogProcessServiceTest, TestTellDumpFinished) { std::shared_ptr monitor = SharedRefBase::make(); std::vector processIdentifiers; processIdentifiers.push_back(constructProcessIdentifier(/*pid=*/1234, /*uid=*/1, /*processName=*/"process", /*startTimeMillis=*/0)); ASSERT_FALSE(mWatchdogProcessService->tellDumpFinished(monitor, processIdentifiers).isOk()) << "Unregistered monitor cannot call tellDumpFinished"; expectLinkToDeath(monitor->asBinder().get(), ScopedAStatus::ok()); mWatchdogProcessService->registerMonitor(monitor); auto status = mWatchdogProcessService->tellDumpFinished(monitor, processIdentifiers); ASSERT_TRUE(status.isOk()) << status.getMessage(); } TEST_F(WatchdogProcessServiceTest, TestCacheAidlVhalPidFromCarWatchdogService) { sp mockServiceHelper = sp::make(); std::shared_ptr mockService = SharedRefBase::make(); const auto binder = mockService->asBinder(); expectRequestAidlVhalPidAndRespond(mockServiceHelper); auto status = mWatchdogProcessService->registerCarWatchdogService(binder, mockServiceHelper); ASSERT_TRUE(status.isOk()) << status.getMessage(); // On processing the TestMessage::ON_AIDL_VHAL_PID, the looper notifies all waiting threads. // Wait for the notification to ensure the VHAL pid caching is satisfied. ASSERT_TRUE(waitForOnAidlVhalPidHandled(kMaxWaitForLooperExecutionMillis)) << "ON_AIDL_VHAL_PID is not handled before timeout"; ASSERT_NO_FATAL_FAILURE(mWatchdogProcessServicePeer->expectVhalProcessIdentifier( ProcessIdentifierEq(constructProcessIdentifier(kTestAidlVhalPid, kTestAidlVhalUid, kTestPidComm, kTestPidStartTime)))); } TEST_F(WatchdogProcessServiceTest, TestFailsCacheAidlVhalPidWithNoCarWatchdogServiceResponse) { sp mockServiceHelper = sp::make(); std::shared_ptr mockService = SharedRefBase::make(); const auto binder = mockService->asBinder(); EXPECT_CALL(*mockServiceHelper, requestAidlVhalPid()) .Times(kMaxVhalPidCachingAttempts) .WillRepeatedly([&]() { // No action taken by CarWatchdogService. return ScopedAStatus::ok(); }); auto status = mWatchdogProcessService->registerCarWatchdogService(binder, mockServiceHelper); ASSERT_TRUE(status.isOk()) << status.getMessage(); // Because CarWatchdogService doesn't respond with the AIDL VHAL pid, wait until all caching // attempts are exhausted to ensure the expected number of caching attempts are satisfied. ASSERT_TRUE(waitUntilVhalPidCachingAttemptsExhausted()) << "Looper not finish handling pending tasks before timeout, probably stuck"; ASSERT_NO_FATAL_FAILURE(mWatchdogProcessServicePeer->expectNoVhalProcessIdentifier()); } TEST_F(WatchdogProcessServiceTest, TestNoCacheAidlVhalPidWithUnsupportedVhalHeartBeatProperty) { // The supported vehicle property list is fetched as soon as VHAL is connected, which happens // during the start of the service. So, restart the service for the new VHAL settings to take // effect. terminateService(); mSupportedVehicleProperties.clear(); mNotSupportedVehicleProperties.push_back(VehicleProperty::VHAL_HEARTBEAT); startService(); sp mockServiceHelper = sp::make(); std::shared_ptr mockService = SharedRefBase::make(); const auto binder = mockService->asBinder(); EXPECT_CALL(*mockServiceHelper, requestAidlVhalPid()).Times(0); auto status = mWatchdogProcessService->registerCarWatchdogService(binder, mockServiceHelper); ASSERT_TRUE(status.isOk()) << status.getMessage(); // VHAL process identifier caching happens on the looper thread. Sync with the looper before // proceeding. ASSERT_TRUE(syncLooper()) << "Looper not finish handling pending tasks before timeout, probably stuck"; ASSERT_NO_FATAL_FAILURE(mWatchdogProcessServicePeer->expectNoVhalProcessIdentifier()); } TEST_F(WatchdogProcessServiceTest, TestCacheHidlVhalPidFromHidlServiceManager) { // VHAL PID caching logic is determined as soon as VHAL is connected, which happens during // the start of the service. So, restart the service for the new VHAL settings to take effect. terminateService(); using InstanceDebugInfo = IServiceManager::InstanceDebugInfo; EXPECT_CALL(*mMockVhalClient, isAidlVhal()).WillOnce(Return(false)); EXPECT_CALL(*mMockHidlServiceManager, debugDump(_)) .WillOnce(Invoke([](IServiceManager::debugDump_cb cb) { cb({InstanceDebugInfo{"android.hardware.automotive.evs@1.0::IEvsCamera", "vehicle_hal_insts", 8058, {}, DebugInfo::Architecture::IS_64BIT}, InstanceDebugInfo{"android.hardware.automotive.vehicle@2.0::IVehicle", "vehicle_hal_insts", static_cast(IServiceManager::PidConstant::NO_PID), {}, DebugInfo::Architecture::IS_64BIT}, InstanceDebugInfo{"android.hardware.automotive.vehicle@2.0::IVehicle", "vehicle_hal_insts", 2034, {}, DebugInfo::Architecture::IS_64BIT}}); return android::hardware::Void(); })); startService(); ASSERT_NO_FATAL_FAILURE(mWatchdogProcessServicePeer->expectVhalProcessIdentifier( ProcessIdentifierEq(constructProcessIdentifier(2034, kTestAidlVhalUid, kTestPidComm, kTestPidStartTime)))); } TEST_F(WatchdogProcessServiceTest, TestFailsCacheHidlVhalPidWithNoHidlVhalService) { // VHAL PID caching logic is determined as soon as VHAL is connected, which happens during // the start of the service. So, restart the service for the new VHAL settings to take effect. terminateService(); using InstanceDebugInfo = IServiceManager::InstanceDebugInfo; EXPECT_CALL(*mMockVhalClient, isAidlVhal()).WillRepeatedly(Return(false)); EXPECT_CALL(*mMockHidlServiceManager, debugDump(_)) .Times(kMaxVhalPidCachingAttempts) .WillRepeatedly(Invoke([](IServiceManager::debugDump_cb cb) { cb({InstanceDebugInfo{"android.hardware.automotive.evs@1.0::IEvsCamera", "vehicle_hal_insts", 8058, {}, DebugInfo::Architecture::IS_64BIT}}); return android::hardware::Void(); })); startService(); // Because HIDL service manager doesn't have the HIDL VHAL pid, wait until all caching // attempts are exhausted to ensure the expected number of caching attempts are satisfied. ASSERT_TRUE(waitUntilVhalPidCachingAttemptsExhausted()) << "Looper not finish handling pending tasks before timeout, probably stuck"; ASSERT_NO_FATAL_FAILURE(mWatchdogProcessServicePeer->expectNoVhalProcessIdentifier()); } TEST_F(WatchdogProcessServiceTest, TestNoCacheHidlVhalPidWithUnsupportedVhalHeartBeatProperty) { // The supported vehicle property list is fetched as soon as VHAL is connected, which happens // during the start of the service. So, restart the service for the new VHAL settings to take // effect. terminateService(); mSupportedVehicleProperties.clear(); mNotSupportedVehicleProperties.push_back(VehicleProperty::VHAL_HEARTBEAT); EXPECT_CALL(*mMockHidlServiceManager, debugDump(_)).Times(0); startService(); ASSERT_NO_FATAL_FAILURE(mWatchdogProcessServicePeer->expectNoVhalProcessIdentifier()); } TEST_F(WatchdogProcessServiceTest, TestOnDumpProto) { ProcessIdentifier processIdentifier; processIdentifier.pid = 1; processIdentifier.uid = kTestAidlClientUid; processIdentifier.processName = "process"; processIdentifier.startTimeMillis = 1000; mWatchdogProcessServicePeer->setWatchdogProcessServiceState(true, nullptr, std::chrono::milliseconds(20000), {101, 102}, processIdentifier); util::ProtoOutputStream proto; mWatchdogProcessService->onDumpProto(proto); CarWatchdogDaemonDump carWatchdogDaemonDump; ASSERT_TRUE(carWatchdogDaemonDump.ParseFromString(toString(&proto))); HealthCheckServiceDump healthCheckServiceDump = carWatchdogDaemonDump.health_check_service_dump(); EXPECT_EQ(healthCheckServiceDump.is_enabled(), true); EXPECT_EQ(healthCheckServiceDump.is_monitor_registered(), false); EXPECT_EQ(healthCheckServiceDump.is_system_shut_down_in_progress(), false); EXPECT_EQ(healthCheckServiceDump.stopped_users_size(), 2); EXPECT_EQ(healthCheckServiceDump.critical_health_check_window_millis(), 20000); EXPECT_EQ(healthCheckServiceDump.moderate_health_check_window_millis(), 20000); EXPECT_EQ(healthCheckServiceDump.normal_health_check_window_millis(), 20000); VhalHealthCheckInfo vhalHealthCheckInfo = healthCheckServiceDump.vhal_health_check_info(); EXPECT_EQ(vhalHealthCheckInfo.is_enabled(), true); EXPECT_EQ(vhalHealthCheckInfo.health_check_window_millis(), (kTestVhalHealthCheckIntervalMillis + kTestVhalHealthCheckDelayMillis).count()); EXPECT_EQ(vhalHealthCheckInfo.pid_caching_progress_state(), VhalHealthCheckInfo_CachingProgressState_SUCCESS); EXPECT_EQ(vhalHealthCheckInfo.pid(), 1); EXPECT_EQ(vhalHealthCheckInfo.start_time_millis(), 1000); EXPECT_EQ(healthCheckServiceDump.registered_client_infos_size(), 1); HealthCheckClientInfo healthCheckClientInfo = healthCheckServiceDump.registered_client_infos(0); EXPECT_EQ(healthCheckClientInfo.pid(), 1); UserPackageInfo userPackageInfo = healthCheckClientInfo.user_package_info(); EXPECT_EQ(userPackageInfo.user_id(), static_cast(multiuser_get_user_id(kTestAidlClientUid))); EXPECT_EQ(userPackageInfo.package_name(), "shell"); EXPECT_EQ(healthCheckClientInfo.client_type(), HealthCheckClientInfo_ClientType_REGULAR); EXPECT_EQ(healthCheckClientInfo.start_time_millis(), 1000); EXPECT_EQ(healthCheckClientInfo.health_check_timeout(), HealthCheckClientInfo_HealthCheckTimeout_CRITICAL); // Clean up test clients before exiting. mWatchdogProcessServicePeer->clearClientsByTimeout(); } TEST_F(WatchdogProcessServiceTest, TestRegisterClientWithPackageName) { std::shared_ptr client = SharedRefBase::make(); ON_CALL(*mMockPackageInfoResolver, asyncFetchPackageNamesForUids(_, _)) .WillByDefault([&](const std::vector& uids, const std::function)>& callback) { callback({{uids[0], "shell"}}); }); ASSERT_FALSE(mWatchdogProcessServicePeer ->hasClientInfoWithPackageName(TimeoutLength::TIMEOUT_CRITICAL, "shell")); ASSERT_FALSE( mWatchdogProcessServicePeer ->hasClientInfoWithProcessName(TimeoutLength::TIMEOUT_CRITICAL, kTestPidComm)); auto status = mWatchdogProcessService->registerClient(client, TimeoutLength::TIMEOUT_CRITICAL); ASSERT_TRUE(mWatchdogProcessServicePeer ->hasClientInfoWithPackageName(TimeoutLength::TIMEOUT_CRITICAL, "shell")); ASSERT_TRUE( mWatchdogProcessServicePeer ->hasClientInfoWithProcessName(TimeoutLength::TIMEOUT_CRITICAL, kTestPidComm)); } TEST_F(WatchdogProcessServiceTest, TestRegisterClientWithPackageNameAndNonExistentUid) { std::shared_ptr client = SharedRefBase::make(); ON_CALL(*mMockPackageInfoResolver, asyncFetchPackageNamesForUids(_, _)) .WillByDefault([&](const std::vector& uids, const std::function)>& callback) { callback({}); ALOGI("No corresponding packageName for uid: %i", uids[0]); }); ASSERT_FALSE(mWatchdogProcessServicePeer ->hasClientInfoWithPackageName(TimeoutLength::TIMEOUT_CRITICAL, "shell")); ASSERT_FALSE( mWatchdogProcessServicePeer ->hasClientInfoWithProcessName(TimeoutLength::TIMEOUT_CRITICAL, kTestPidComm)); auto status = mWatchdogProcessService->registerClient(client, TimeoutLength::TIMEOUT_CRITICAL); ASSERT_FALSE(mWatchdogProcessServicePeer ->hasClientInfoWithPackageName(TimeoutLength::TIMEOUT_CRITICAL, "shell")); ASSERT_TRUE( mWatchdogProcessServicePeer ->hasClientInfoWithProcessName(TimeoutLength::TIMEOUT_CRITICAL, kTestPidComm)); } TEST_F(WatchdogProcessServiceTest, TestDumpAndKillAllProcessesDuringGarageMode) { if (!car_watchdog_anr_metrics()) { GTEST_SKIP() << "car_watchdog_anr_metrics feature flag is not enabled"; } auto status = mWatchdogProcessService->registerMonitor(mMockWatchdogMonitor); ASSERT_TRUE(status.isOk()) << status.getMessage(); mWatchdogProcessService->setGarageMode(GarageMode::GARAGE_MODE_ON); std::vector processIdentifiers; processIdentifiers.push_back(constructProcessIdentifier(/*pid=*/111, /*uid=*/1, /*processName=*/"process1", /*startTimeMillis=*/0)); processIdentifiers.push_back(constructProcessIdentifier(/*pid=*/222, /*uid=*/2, /*processName=*/"process2", /*startTimeMillis=*/0)); ClientsNotRespondingInfo clientsNotRespondingInfo = { .processIdentifiers = processIdentifiers, .garageMode = GarageMode::GARAGE_MODE_ON, }; EXPECT_CALL(*mMockWatchdogMonitor, onClientsNotRespondingWithSystemState( ClientsNotRespondingInfoEq(clientsNotRespondingInfo))) .Times(1); // TODO(b/388042850): Update to use end-to-end implementation mWatchdogProcessServicePeer->dumpAndKillAllProcesses(processIdentifiers, /*reportToVhal=*/false); } TEST_F(WatchdogProcessServiceTest, TestDumpAndKillAllProcesses) { if (!car_watchdog_anr_metrics()) { GTEST_SKIP() << "car_watchdog_anr_metrics feature flag is not enabled"; } auto status = mWatchdogProcessService->registerMonitor(mMockWatchdogMonitor); ASSERT_TRUE(status.isOk()) << status.getMessage(); mWatchdogProcessService->setGarageMode(GarageMode::GARAGE_MODE_OFF); std::vector processIdentifiers; processIdentifiers.push_back(constructProcessIdentifier(/*pid=*/111, /*uid=*/1, /*processName=*/"process1", /*startTimeMillis=*/0)); processIdentifiers.push_back(constructProcessIdentifier(/*pid=*/222, /*uid=*/2, /*processName=*/"process2", /*startTimeMillis=*/0)); ClientsNotRespondingInfo clientsNotRespondingInfo = { .processIdentifiers = processIdentifiers, .garageMode = GarageMode::GARAGE_MODE_OFF, }; EXPECT_CALL(*mMockWatchdogMonitor, onClientsNotRespondingWithSystemState( ClientsNotRespondingInfoEq(clientsNotRespondingInfo))) .Times(1); // TODO(b/388042850): Update to use end-to-end implementation mWatchdogProcessServicePeer->dumpAndKillAllProcesses(processIdentifiers, /*reportToVhal=*/false); } TEST_F(WatchdogProcessServiceTest, TestDumpAndKillAllProcessesWithAnrMetricsFeatureDisabled) { if (car_watchdog_anr_metrics()) { GTEST_SKIP() << "car_watchdog_anr_metrics feature flag is not disabled"; } auto status = mWatchdogProcessService->registerMonitor(mMockWatchdogMonitor); ASSERT_TRUE(status.isOk()) << status.getMessage(); std::vector processIdentifiers; processIdentifiers.push_back(constructProcessIdentifier(/*pid=*/111, /*uid=*/1, /*processName=*/"process1", /*startTimeMillis=*/0)); processIdentifiers.push_back(constructProcessIdentifier(/*pid=*/222, /*uid=*/2, /*processName=*/"process2", /*startTimeMillis=*/0)); EXPECT_CALL(*mMockWatchdogMonitor, onClientsNotResponding(UnorderedElementsAreArray( constructProcessIdentifierMatchers(processIdentifiers)))) .Times(1); // TODO(b/388042850): Update to use end-to-end implementation mWatchdogProcessServicePeer->dumpAndKillAllProcesses(processIdentifiers, /*reportToVhal=*/false); } class TestCarWatchdogMonitor : public BnCarWatchdogMonitor { public: ScopedAStatus onClientsNotResponding(const std::vector& pids) override { { std::lock_guard lock(mMutex); mKilledPids = pids; } mCv.notify_all(); return ScopedAStatus::ok(); } ScopedAStatus onClientsNotRespondingWithSystemState( [[maybe_unused]] const ClientsNotRespondingInfo& clientsNotRespondingInfo) override { { std::lock_guard lock(mMutex); mKilledPids = clientsNotRespondingInfo.processIdentifiers; } mCv.notify_all(); return ScopedAStatus::ok(); } bool waitForPidsKilled(std::chrono::milliseconds timeoutInMs) { std::unique_lock lock(mMutex); return mCv.wait_for(lock, timeoutInMs, [this] { return mKilledPids.size() != 0; }); } std::vector getKilledPids() { std::lock_guard lock(mMutex); return mKilledPids; } private: std::mutex mMutex; std::condition_variable mCv GUARDED_BY(mMutex); std::vector mKilledPids GUARDED_BY(mMutex); }; // Verifies that if VHAL updates VHAL_HEARTBEAT property according to requirement, carwatchdog // will not kill VHAL. TEST_F(WatchdogProcessServiceTest, TestSuccessfulVhalHeartBeatUpdate) { // Restart service to support all properties. terminateService(); mSupportedVehicleProperties = {VehicleProperty::VHAL_HEARTBEAT, VehicleProperty::WATCHDOG_ALIVE, VehicleProperty::WATCHDOG_TERMINATED_PROCESS}; mNotSupportedVehicleProperties = {}; startService(); ASSERT_NO_FATAL_FAILURE(setupMockCarServiceAndWaitForAidlVhalPidFetched()); std::shared_ptr monitor = SharedRefBase::make(); auto status = mWatchdogProcessService->registerMonitor(monitor); ASSERT_TRUE(status.isOk()) << status.getMessage(); ASSERT_TRUE(waitForSubscribedCallbackSet(1s)) << "IVehicle.subscribe is not called"; scheduleVhalHeartBeatUpdate(); ASSERT_FALSE(monitor->waitForPidsKilled(1s)) << "VHAL should not be killed"; } // Verifies that if VHAL does not update VHAL_HEARTBEAT, carwatchdog should kill VHAL. TEST_F(WatchdogProcessServiceTest, TestKillVhalOnMissingVhalHeartBeatUpdate) { // Restart service to support all properties. terminateService(); mSupportedVehicleProperties = {VehicleProperty::VHAL_HEARTBEAT, VehicleProperty::WATCHDOG_ALIVE, VehicleProperty::WATCHDOG_TERMINATED_PROCESS}; mNotSupportedVehicleProperties = {}; startService(); ASSERT_NO_FATAL_FAILURE(setupMockCarServiceAndWaitForAidlVhalPidFetched()); std::shared_ptr monitor = SharedRefBase::make(); auto status = mWatchdogProcessService->registerMonitor(monitor); ASSERT_TRUE(status.isOk()) << status.getMessage(); // The check interval is 200ms, delay is 100ms, so we should expect to see the kill around // 300ms, wait for 1s to be safe. ASSERT_TRUE(monitor->waitForPidsKilled(1s)) << "Expect not-responding pids to be killed"; const auto& killedPids = monitor->getKilledPids(); ASSERT_THAT(killedPids, SizeIs(1)); ASSERT_THAT(killedPids[0].pid, kTestAidlVhalPid); } // Verifies that if VHAL updates VHAL_HEARTBEAT too slow, carwatchdog should kill VHAL. TEST_F(WatchdogProcessServiceTest, TestKillVhalOnDelayedVhalHeartBeatSecondUpdate) { // Restart service to support all properties. terminateService(); mSupportedVehicleProperties = {VehicleProperty::VHAL_HEARTBEAT, VehicleProperty::WATCHDOG_ALIVE, VehicleProperty::WATCHDOG_TERMINATED_PROCESS}; mNotSupportedVehicleProperties = {}; startService(); ASSERT_NO_FATAL_FAILURE(setupMockCarServiceAndWaitForAidlVhalPidFetched()); std::shared_ptr monitor = SharedRefBase::make(); auto status = mWatchdogProcessService->registerMonitor(monitor); ASSERT_TRUE(status.isOk()) << status.getMessage(); ASSERT_TRUE(waitForSubscribedCallbackSet(1s)) << "IVehicle.subscribe is not called"; // Schedule the first heart beat update to happen immediately. But set the update interval to // trigger the second heart beat update to happen outside the allowed health check window // (300ms). // This should trigger the watchdog killing after the first update and before the delayed // second update. setVhalHeartbeatUpdateInterval(400ms); scheduleVhalHeartBeatUpdate(); // We expect the kill to happen around 300ms, set this to 1s to be safe. ASSERT_TRUE(monitor->waitForPidsKilled(1s)) << "Expect not-responding pids to be killed"; const auto& killedPids = monitor->getKilledPids(); ASSERT_THAT(killedPids, SizeIs(1)); ASSERT_THAT(killedPids[0].pid, kTestAidlVhalPid); } // Verifies that if the first VHAL_HEARTBEAT arrives too late, carwatchdog should kill VHAL. TEST_F(WatchdogProcessServiceTest, TestKillVhalOnDelayedVhalHeartBeatFirstUpdate) { // Restart service to support all properties. terminateService(); mSupportedVehicleProperties = {VehicleProperty::VHAL_HEARTBEAT, VehicleProperty::WATCHDOG_ALIVE, VehicleProperty::WATCHDOG_TERMINATED_PROCESS}; mNotSupportedVehicleProperties = {}; startService(); ASSERT_NO_FATAL_FAILURE(setupMockCarServiceAndWaitForAidlVhalPidFetched()); std::shared_ptr monitor = SharedRefBase::make(); auto status = mWatchdogProcessService->registerMonitor(monitor); ASSERT_TRUE(status.isOk()) << status.getMessage(); ASSERT_TRUE(waitForSubscribedCallbackSet(1s)) << "IVehicle.subscribe is not called"; // Schedule the first heart beat update to happen outside the allowed health check window // (300ms) to trigger the watchdog killing before the first heart beat update. scheduleVhalHeartBeatUpdate(400ms); ASSERT_TRUE(monitor->waitForPidsKilled(1s)) << "Expect not-responding pids to be killed"; const auto& killedPids = monitor->getKilledPids(); ASSERT_THAT(killedPids, SizeIs(1)); ASSERT_THAT(killedPids[0].pid, kTestAidlVhalPid); } } // namespace watchdog } // namespace automotive } // namespace android