/* * 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 "MockCarWatchdogServiceForSystem.h" #include "MockVhalClient.h" #include "MockWatchdogServiceHelper.h" #include "WatchdogProcessService.h" #include "WatchdogServiceHelper.h" #include #include #include namespace android { namespace automotive { namespace watchdog { namespace aawi = ::android::automotive::watchdog::internal; namespace afav = ::android::frameworks::automotive::vhal; namespace aahav = ::aidl::android::hardware::automotive::vehicle; using aahav::VehicleProperty; using aawi::ProcessIdentifier; using ::android::IBinder; using ::android::sp; using ::android::binder::Status; using ::ndk::SharedRefBase; using ::testing::_; using ::testing::ByMove; using ::testing::Return; namespace { class MockCarWatchdogClient : public ICarWatchdogClientDefault { public: MockCarWatchdogClient() { mBinder = sp::make(); } sp getBinder() const { return mBinder; } MOCK_METHOD(IBinder*, onAsBinder, (), (override)); private: sp mBinder; }; class MockCarWatchdogMonitor : public aawi::ICarWatchdogMonitorDefault { public: MockCarWatchdogMonitor() { mBinder = sp::make(); } sp getBinder() const { return mBinder; } MOCK_METHOD(IBinder*, onAsBinder, (), (override)); private: sp mBinder; }; ProcessIdentifier constructProcessIdentifier(int32_t pid, int64_t startTimeMillis) { ProcessIdentifier processIdentifier; processIdentifier.pid = pid; processIdentifier.startTimeMillis = startTimeMillis; return processIdentifier; } } // namespace namespace internal { class WatchdogProcessServicePeer final { public: explicit WatchdogProcessServicePeer(const sp& watchdogProcessService) : mWatchdogProcessService(watchdogProcessService) { mWatchdogProcessService->mGetStartTimeForPidFunc = [](pid_t) -> uint64_t { return 12356; }; } void setVhalService(std::shared_ptr service) { mWatchdogProcessService->mVhalService = service; } void setNotSupportedVhalProperties(const std::unordered_set& properties) { mWatchdogProcessService->mNotSupportedVhalProperties = properties; } private: sp mWatchdogProcessService; }; } // namespace internal class WatchdogProcessServiceTest : public ::testing::Test { protected: void SetUp() override { sp looper(Looper::prepare(/*opts=*/0)); mWatchdogProcessService = sp::make(looper); mMockVehicle = SharedRefBase::make(); mMockVhalClient = std::make_shared(mMockVehicle); internal::WatchdogProcessServicePeer peer(mWatchdogProcessService); peer.setVhalService(mMockVhalClient); peer.setNotSupportedVhalProperties( {VehicleProperty::WATCHDOG_ALIVE, VehicleProperty::WATCHDOG_TERMINATED_PROCESS}); mWatchdogProcessService->start(); } void TearDown() override { mWatchdogProcessService->terminate(); mWatchdogProcessService.clear(); mMockVhalClient.reset(); mMockVehicle.reset(); } sp mWatchdogProcessService; std::shared_ptr mMockVhalClient; std::shared_ptr mMockVehicle; }; sp createMockCarWatchdogClient(status_t linkToDeathResult) { sp client = sp::make(); sp binder = client->getBinder(); EXPECT_CALL(*binder, linkToDeath(_, nullptr, 0)).WillRepeatedly(Return(linkToDeathResult)); EXPECT_CALL(*binder, unlinkToDeath(_, nullptr, 0, nullptr)).WillRepeatedly(Return(OK)); EXPECT_CALL(*client, onAsBinder()).WillRepeatedly(Return(binder.get())); return client; } sp createMockCarWatchdogMonitor(status_t linkToDeathResult) { sp monitor = sp::make(); sp binder = monitor->getBinder(); EXPECT_CALL(*binder, linkToDeath(_, nullptr, 0)).WillRepeatedly(Return(linkToDeathResult)); EXPECT_CALL(*binder, unlinkToDeath(_, nullptr, 0, nullptr)).WillRepeatedly(Return(OK)); EXPECT_CALL(*monitor, onAsBinder()).WillRepeatedly(Return(binder.get())); return monitor; } sp expectNormalCarWatchdogClient() { return createMockCarWatchdogClient(OK); } sp expectCarWatchdogClientBinderDied() { return createMockCarWatchdogClient(DEAD_OBJECT); } sp expectNormalCarWatchdogMonitor() { return createMockCarWatchdogMonitor(OK); } sp expectCarWatchdogMonitorBinderDied() { return createMockCarWatchdogMonitor(DEAD_OBJECT); } TEST_F(WatchdogProcessServiceTest, TestTerminate) { std::vector propIds = {static_cast(aahav::VehicleProperty::VHAL_HEARTBEAT)}; EXPECT_CALL(*mMockVhalClient, removeOnBinderDiedCallback(_)).Times(1); EXPECT_CALL(*mMockVehicle, unsubscribe(_, propIds)) .WillOnce(Return(ByMove(std::move(ndk::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) { sp client = expectNormalCarWatchdogClient(); Status status = mWatchdogProcessService->registerClient(client, TimeoutLength::TIMEOUT_CRITICAL); ASSERT_TRUE(status.isOk()) << status; status = mWatchdogProcessService->registerClient(client, TimeoutLength::TIMEOUT_CRITICAL); ASSERT_TRUE(status.isOk()) << status; } TEST_F(WatchdogProcessServiceTest, TestUnregisterClient) { sp client = expectNormalCarWatchdogClient(); mWatchdogProcessService->registerClient(client, TimeoutLength::TIMEOUT_CRITICAL); Status status = mWatchdogProcessService->unregisterClient(client); ASSERT_TRUE(status.isOk()) << status; ASSERT_FALSE(mWatchdogProcessService->unregisterClient(client).isOk()) << "Unregistering an unregistered client should return an error"; } TEST_F(WatchdogProcessServiceTest, TestErrorOnRegisterClientWithDeadBinder) { sp client = expectCarWatchdogClientBinderDied(); ASSERT_FALSE( mWatchdogProcessService->registerClient(client, TimeoutLength::TIMEOUT_CRITICAL).isOk()) << "When linkToDeath fails, registerClient should return an error"; } TEST_F(WatchdogProcessServiceTest, TestRegisterCarWatchdogService) { sp mockServiceHelper = sp::make(); ASSERT_RESULT_OK(mWatchdogProcessService->registerWatchdogServiceHelper(mockServiceHelper)); sp mockService = sp::make(); sp binder = mockService->getBinder(); Status status = mWatchdogProcessService->registerCarWatchdogService(binder); ASSERT_TRUE(status.isOk()) << status; status = mWatchdogProcessService->registerCarWatchdogService(binder); ASSERT_TRUE(status.isOk()) << status; } TEST_F(WatchdogProcessServiceTest, TestErrorOnRegisterCarWatchdogServiceWithUninitializedWatchdogServiceHelper) { sp mockService = sp::make(); sp binder = mockService->getBinder(); ASSERT_FALSE(mWatchdogProcessService->registerCarWatchdogService(binder).isOk()) << "Registering car watchdog service should fail when watchdog service helper is " "uninitialized"; } TEST_F(WatchdogProcessServiceTest, TestRegisterMonitor) { sp monitorOne = expectNormalCarWatchdogMonitor(); sp monitorTwo = expectNormalCarWatchdogMonitor(); Status status = mWatchdogProcessService->registerMonitor(monitorOne); ASSERT_TRUE(status.isOk()) << status; status = mWatchdogProcessService->registerMonitor(monitorOne); ASSERT_TRUE(status.isOk()) << status; status = mWatchdogProcessService->registerMonitor(monitorTwo); ASSERT_TRUE(status.isOk()) << status; } TEST_F(WatchdogProcessServiceTest, TestErrorOnRegisterMonitorWithDeadBinder) { sp monitor = expectCarWatchdogMonitorBinderDied(); ASSERT_FALSE(mWatchdogProcessService->registerMonitor(monitor).isOk()) << "When linkToDeath fails, registerMonitor should return an error"; } TEST_F(WatchdogProcessServiceTest, TestUnregisterMonitor) { sp monitor = expectNormalCarWatchdogMonitor(); mWatchdogProcessService->registerMonitor(monitor); Status status = mWatchdogProcessService->unregisterMonitor(monitor); ASSERT_TRUE(status.isOk()) << status; ASSERT_FALSE(mWatchdogProcessService->unregisterMonitor(monitor).isOk()) << "Unregistering an unregistered monitor should return an error"; } TEST_F(WatchdogProcessServiceTest, TestTellClientAlive) { sp client = expectNormalCarWatchdogClient(); 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) { sp mockServiceHelper = sp::make(); ASSERT_RESULT_OK(mWatchdogProcessService->registerWatchdogServiceHelper(mockServiceHelper)); sp mockService = sp::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) { sp monitor = expectNormalCarWatchdogMonitor(); ASSERT_FALSE(mWatchdogProcessService ->tellDumpFinished(monitor, constructProcessIdentifier(/* pid= */ 1234, /* startTimeMillis= */ 0)) .isOk()) << "Unregistered monitor cannot call tellDumpFinished"; mWatchdogProcessService->registerMonitor(monitor); Status status = mWatchdogProcessService ->tellDumpFinished(monitor, constructProcessIdentifier(/* pid= */ 1234, /* startTimeMillis= */ 0)); ASSERT_TRUE(status.isOk()) << status; } } // namespace watchdog } // namespace automotive } // namespace android