/* * 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 "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 // 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::ICarWatchdogMonitor; using ::aidl::android::automotive::watchdog::internal::ICarWatchdogMonitorDefault; using ::aidl::android::automotive::watchdog::internal::ProcessIdentifier; using ::aidl::android::hardware::automotive::vehicle::VehicleProperty; using ::android::IBinder; using ::android::Looper; using ::android::sp; using ::android::base::Error; 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::Return; namespace { constexpr std::chrono::milliseconds kMaxWaitForLooperExecutionMillis = 5s; constexpr std::chrono::nanoseconds kTestVhalPidCachingRetryDelayNs = 20ms; constexpr char kTestLooperThreadName[] = "WdProcSvcTest"; constexpr const int32_t kTestAidlVhalPid = 564269; constexpr const int32_t kTestPidStartTime = 12356; constexpr const int32_t kMaxVhalPidCachingAttempts = 2; enum TestMessage { NOTIFY_ALL, ON_AIDL_VHAL_PID, }; ProcessIdentifier constructProcessIdentifier(int32_t pid, int64_t startTimeMillis) { ProcessIdentifier processIdentifier; processIdentifier.pid = pid; processIdentifier.startTimeMillis = startTimeMillis; return processIdentifier; } MATCHER_P(ProcessIdentifierEq, expected, "") { return ExplainMatchResult(AllOf(Field("pid", &ProcessIdentifier::pid, Eq(expected.pid)), Field("startTimeMillis", &ProcessIdentifier::startTimeMillis, Eq(expected.startTimeMillis))), arg, result_listener); } } // namespace namespace internal { class WatchdogProcessServicePeer final { public: explicit WatchdogProcessServicePeer(const sp& watchdogProcessService) : mWatchdogProcessService(watchdogProcessService) {} 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, std::chrono::milliseconds vhalHealthCheckWindowMillis, const ProcessIdentifier& processIdentifier) { Mutex::Autolock lock(mWatchdogProcessService->mMutex); mWatchdogProcessService->mIsEnabled = isEnabled; mWatchdogProcessService->mMonitor = monitor; mWatchdogProcessService->mOverriddenClientHealthCheckWindowNs = overriddenClientHealthCheckWindowNs; mWatchdogProcessService->mStoppedUserIds = stoppedUserIds; mWatchdogProcessService->mVhalHealthCheckWindowMillis = vhalHealthCheckWindowMillis; mWatchdogProcessService->mVhalProcessIdentifier = processIdentifier; WatchdogProcessService::ClientInfoMap clientInfoMap; WatchdogProcessService::ClientInfo clientInfo(nullptr, 1, 1, 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(); } 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; } void setPackageInfoResolver(const sp& packageInfoResolver) { mWatchdogProcessService->mPackageInfoResolver = packageInfoResolver; } private: sp mWatchdogProcessService; }; } // namespace internal class WatchdogProcessServiceTest : public ::testing::Test { public: WatchdogProcessServiceTest() : mMockVhalClient(nullptr), mMockHidlServiceManager(nullptr), kTryCreateVhalClientFunc([this]() { return mMockVhalClient; }), kTryGetHidlServiceManagerFunc([this]() { return mMockHidlServiceManager; }), kGetStartTimeForPidFunc([](pid_t) { return kTestPidStartTime; }) {} 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 = sp::make(); startService(); } void TearDown() override { terminateService(); mMockDeathRegistrationWrapper.clear(); mMockHidlServiceManager.clear(); mMockVhalClient.reset(); mMockVehicle.reset(); mMessageHandler.clear(); mMockPackageInfoResolver.clear(); } void startService() { prepareLooper(); mWatchdogProcessService = sp::make(kTryCreateVhalClientFunc, kTryGetHidlServiceManagerFunc, kGetStartTimeForPidFunc, kTestVhalPidCachingRetryDelayNs, mHandlerLooper, mMockDeathRegistrationWrapper); mWatchdogProcessServicePeer = std::make_unique(mWatchdogProcessService); mWatchdogProcessServicePeer->setPackageInfoResolver(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. syncLooper(); } void terminateService() { wakeAndJoinLooper(); mWatchdogProcessServicePeer.reset(); mWatchdogProcessService->terminate(); mWatchdogProcessService.clear(); mHandlerLooper.clear(); } 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(); }); } void syncLooper(std::chrono::nanoseconds delay = 0ns) { // Acquire the lock before sending message to avoid any race condition. std::unique_lock lock(mMutex); mHandlerLooper->sendMessageDelayed(delay.count(), mMessageHandler, Message(TestMessage::NOTIFY_ALL)); waitForLooperNotificationLocked(lock, delay); } void waitForLooperNotification(std::chrono::nanoseconds delay = 0ns) { std::unique_lock lock(mMutex); waitForLooperNotificationLocked(lock, delay); } void waitForLooperNotificationLocked(std::unique_lock& lock, std::chrono::nanoseconds delay = 0ns) { // If a race condition is detected in the handler looper, the current locking mechanism // should be re-evaluated as discussed in b/299676049. std::cv_status status = mLooperCondition .wait_for(lock, kMaxWaitForLooperExecutionMillis + std::chrono::duration_cast( delay)); ASSERT_EQ(status, std::cv_status::no_timeout) << "Looper notification not received"; } void waitUntilVhalPidCachingAttemptsExhausted() { 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; } sp mWatchdogProcessService; std::unique_ptr mWatchdogProcessServicePeer; std::shared_ptr mMockVhalClient; std::shared_ptr mMockVehicle; sp mMockHidlServiceManager; sp mMockDeathRegistrationWrapper; std::vector mSupportedVehicleProperties; std::vector mNotSupportedVehicleProperties; sp mMockPackageInfoResolver; 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::NOTIFY_ALL): break; case static_cast(TestMessage::ON_AIDL_VHAL_PID): mTest->mWatchdogProcessService->onAidlVhalPidFetched(kTestAidlVhalPid); break; default: ALOGE("Unknown TestMessage: %d", message.what); return; } std::unique_lock 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 = Looper::prepare(/*opts=*/0); 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(); } } const std::function()> kTryCreateVhalClientFunc; const std::function()> kTryGetHidlServiceManagerFunc; const std::function kGetStartTimeForPidFunc; sp mHandlerLooper; sp mMessageHandler; std::thread mHandlerLooperThread; mutable std::mutex mMutex; std::condition_variable mLooperCondition GUARDED_BY(mMutex); std::atomic mShouldTerminateLooper; }; 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(std::move(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(), std::move(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, std::move(ScopedAStatus::ok())); auto status = mWatchdogProcessService->registerClient(client, TimeoutLength::TIMEOUT_CRITICAL); ASSERT_TRUE(status.isOk()) << status.getMessage(); expectUnlinkToDeath(aiBinder, std::move(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(), std::move(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, std::move(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(std::move(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. syncLooper(); // 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(), std::move(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(), std::move(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, std::move(ScopedAStatus::ok())); auto status = mWatchdogProcessService->registerMonitor(monitor); ASSERT_TRUE(status.isOk()) << status.getMessage(); expectUnlinkToDeath(aiBinder, std::move(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, std::move(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(), std::move(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, /* startTimeMillis= */ 0)); processIdentifiers.push_back( constructProcessIdentifier(/* pid= */ 222, /* 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(); ASSERT_FALSE(mWatchdogProcessService ->tellDumpFinished(monitor, constructProcessIdentifier(/* pid= */ 1234, /* startTimeMillis= */ 0)) .isOk()) << "Unregistered monitor cannot call tellDumpFinished"; expectLinkToDeath(monitor->asBinder().get(), std::move(ScopedAStatus::ok())); mWatchdogProcessService->registerMonitor(monitor); auto status = mWatchdogProcessService ->tellDumpFinished(monitor, constructProcessIdentifier(/* pid= */ 1234, /* startTimeMillis= */ 0)); 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. waitForLooperNotification(); ASSERT_NO_FATAL_FAILURE(mWatchdogProcessServicePeer->expectVhalProcessIdentifier( ProcessIdentifierEq(constructProcessIdentifier(kTestAidlVhalPid, 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. waitUntilVhalPidCachingAttemptsExhausted(); 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. syncLooper(); 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, 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. waitUntilVhalPidCachingAttemptsExhausted(); 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.startTimeMillis = 1000; mWatchdogProcessServicePeer->setWatchdogProcessServiceState(true, nullptr, std::chrono::milliseconds(20000), {101, 102}, std::chrono::milliseconds(10000), 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(), 10000); 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(), 1); 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")); auto status = mWatchdogProcessService->registerClient(client, TimeoutLength::TIMEOUT_CRITICAL); ASSERT_TRUE(mWatchdogProcessServicePeer ->hasClientInfoWithPackageName(TimeoutLength::TIMEOUT_CRITICAL, "shell")); } 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")); auto status = mWatchdogProcessService->registerClient(client, TimeoutLength::TIMEOUT_CRITICAL); ASSERT_FALSE(mWatchdogProcessServicePeer ->hasClientInfoWithPackageName(TimeoutLength::TIMEOUT_CRITICAL, "shell")); } } // namespace watchdog } // namespace automotive } // namespace android