unplugged-system/packages/services/Car/cpp/watchdog/server/tests/WatchdogProcessServiceTest.cpp

684 lines
30 KiB
C++

/*
* 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 "MockVhalClient.h"
#include "MockWatchdogServiceHelper.h"
#include "WatchdogProcessService.h"
#include "WatchdogServiceHelper.h"
#include <android/binder_interface_utils.h>
#include <android/hidl/manager/1.0/IServiceManager.h>
#include <gmock/gmock.h>
#include <thread> // NOLINT(build/c++11)
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 ::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>& watchdogProcessService) :
mWatchdogProcessService(watchdogProcessService) {}
void expectVhalProcessIdentifier(const Matcher<const ProcessIdentifier&> 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());
}
private:
sp<WatchdogProcessService> 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<MessageHandlerImpl>::make(this);
mMockVehicle = SharedRefBase::make<MockVehicle>();
mMockVhalClient = std::make_shared<MockVhalClient>(mMockVehicle);
mMockHidlServiceManager = sp<MockHidlServiceManager>::make();
mMockDeathRegistrationWrapper = sp<MockAIBinderDeathRegistrationWrapper>::make();
mSupportedVehicleProperties = {VehicleProperty::VHAL_HEARTBEAT};
mNotSupportedVehicleProperties = {VehicleProperty::WATCHDOG_ALIVE,
VehicleProperty::WATCHDOG_TERMINATED_PROCESS};
startService();
}
void TearDown() override {
terminateService();
mMockDeathRegistrationWrapper.clear();
mMockHidlServiceManager.clear();
mMockVhalClient.reset();
mMockVehicle.reset();
mMessageHandler.clear();
}
void startService() {
prepareLooper();
mWatchdogProcessService =
sp<WatchdogProcessService>::make(kTryCreateVhalClientFunc,
kTryGetHidlServiceManagerFunc,
kGetStartTimeForPidFunc,
kTestVhalPidCachingRetryDelayNs, mHandlerLooper,
mMockDeathRegistrationWrapper);
mWatchdogProcessServicePeer =
std::make_unique<internal::WatchdogProcessServicePeer>(mWatchdogProcessService);
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<void*>(aiBinder)))
.WillOnce(Return(ByMove(std::move(expectedStatus))));
}
void expectUnlinkToDeath(AIBinder* aiBinder, ScopedAStatus expectedStatus) {
EXPECT_CALL(*mMockDeathRegistrationWrapper,
unlinkToDeath(Eq(aiBinder), _, static_cast<void*>(aiBinder)))
.WillOnce(Return(ByMove(std::move(expectedStatus))));
}
void expectNoUnlinkToDeath(AIBinder* aiBinder) {
EXPECT_CALL(*mMockDeathRegistrationWrapper,
unlinkToDeath(Eq(aiBinder), _, static_cast<void*>(aiBinder)))
.Times(0);
}
void expectGetPropConfigs(const std::vector<VehicleProperty>& supportedProperties,
const std::vector<VehicleProperty>& notSupportedProperties) {
for (const auto& propId : supportedProperties) {
EXPECT_CALL(*mMockVhalClient,
getPropConfigs(std::vector<int32_t>{static_cast<int32_t>(propId)}))
.WillOnce([]() { return std::vector<std::unique_ptr<IHalPropConfig>>(); });
}
for (const auto& propId : notSupportedProperties) {
EXPECT_CALL(*mMockVhalClient,
getPropConfigs(std::vector<int32_t>{static_cast<int32_t>(propId)}))
.WillOnce(
[]() -> VhalClientResult<std::vector<std::unique_ptr<IHalPropConfig>>> {
return Error<VhalClientError>(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<MockWatchdogServiceHelper>& 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) {
mHandlerLooper->sendMessageDelayed(delay.count(), mMessageHandler,
Message(TestMessage::NOTIFY_ALL));
waitForLooperNotification(delay);
}
void waitForLooperNotification(std::chrono::nanoseconds delay = 0ns) {
std::unique_lock lock(mMutex);
mLooperCondition.wait_for(lock,
kMaxWaitForLooperExecutionMillis +
std::chrono::duration_cast<std::chrono::milliseconds>(
delay));
}
void waitUntilVhalPidCachingAttemptsExhausted() {
syncLooper((kMaxVhalPidCachingAttempts + 1) * kTestVhalPidCachingRetryDelayNs);
}
sp<WatchdogProcessService> mWatchdogProcessService;
std::unique_ptr<internal::WatchdogProcessServicePeer> mWatchdogProcessServicePeer;
std::shared_ptr<MockVhalClient> mMockVhalClient;
std::shared_ptr<MockVehicle> mMockVehicle;
sp<MockHidlServiceManager> mMockHidlServiceManager;
sp<MockAIBinderDeathRegistrationWrapper> mMockDeathRegistrationWrapper;
std::vector<VehicleProperty> mSupportedVehicleProperties;
std::vector<VehicleProperty> mNotSupportedVehicleProperties;
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<int>(TestMessage::NOTIFY_ALL):
break;
case static_cast<int>(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<std::shared_ptr<IVhalClient>()> kTryCreateVhalClientFunc;
const std::function<android::sp<android::hidl::manager::V1_0::IServiceManager>()>
kTryGetHidlServiceManagerFunc;
const std::function<int64_t(pid_t)> kGetStartTimeForPidFunc;
sp<Looper> mHandlerLooper;
sp<MessageHandlerImpl> mMessageHandler;
std::thread mHandlerLooperThread;
mutable std::mutex mMutex;
std::condition_variable mLooperCondition GUARDED_BY(mMutex);
std::atomic<bool> mShouldTerminateLooper;
};
TEST_F(WatchdogProcessServiceTest, TestTerminate) {
std::vector<int32_t> propIds = {static_cast<int32_t>(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<ICarWatchdogClient> client = SharedRefBase::make<ICarWatchdogClientDefault>();
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<ICarWatchdogClient> client = SharedRefBase::make<ICarWatchdogClientDefault>();
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<ICarWatchdogClient> client = SharedRefBase::make<ICarWatchdogClientDefault>();
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<ICarWatchdogClient> client = SharedRefBase::make<ICarWatchdogClientDefault>();
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<void*>(aiBinder));
expectNoUnlinkToDeath(aiBinder);
ASSERT_FALSE(mWatchdogProcessService->unregisterClient(client).isOk())
<< "Unregistering a dead client should return an error";
}
TEST_F(WatchdogProcessServiceTest, TestRegisterCarWatchdogService) {
sp<MockWatchdogServiceHelper> mockServiceHelper = sp<MockWatchdogServiceHelper>::make();
std::shared_ptr<MockCarWatchdogServiceForSystem> mockService =
SharedRefBase::make<MockCarWatchdogServiceForSystem>();
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<MockCarWatchdogServiceForSystem> mockService =
SharedRefBase::make<MockCarWatchdogServiceForSystem>();
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<ICarWatchdogMonitor> monitorOne =
SharedRefBase::make<ICarWatchdogMonitorDefault>();
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<ICarWatchdogMonitor> monitorTwo =
SharedRefBase::make<ICarWatchdogMonitorDefault>();
status = mWatchdogProcessService->registerMonitor(monitorTwo);
ASSERT_TRUE(status.isOk()) << status.getMessage();
}
TEST_F(WatchdogProcessServiceTest, TestErrorOnRegisterMonitorWithDeadBinder) {
std::shared_ptr<ICarWatchdogMonitor> monitor =
SharedRefBase::make<ICarWatchdogMonitorDefault>();
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<ICarWatchdogMonitor> monitor =
SharedRefBase::make<ICarWatchdogMonitorDefault>();
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<ICarWatchdogMonitor> monitor =
SharedRefBase::make<ICarWatchdogMonitorDefault>();
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<void*>(aiBinder));
expectNoUnlinkToDeath(aiBinder);
ASSERT_FALSE(mWatchdogProcessService->unregisterMonitor(monitor).isOk())
<< "Unregistering a dead monitor should return an error";
}
TEST_F(WatchdogProcessServiceTest, TestTellClientAlive) {
std::shared_ptr<ICarWatchdogClient> client = SharedRefBase::make<ICarWatchdogClientDefault>();
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<MockCarWatchdogServiceForSystem> mockService =
SharedRefBase::make<MockCarWatchdogServiceForSystem>();
std::vector<ProcessIdentifier> 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<ICarWatchdogMonitor> monitor =
SharedRefBase::make<ICarWatchdogMonitorDefault>();
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<MockWatchdogServiceHelper> mockServiceHelper = sp<MockWatchdogServiceHelper>::make();
std::shared_ptr<MockCarWatchdogServiceForSystem> mockService =
SharedRefBase::make<MockCarWatchdogServiceForSystem>();
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<MockWatchdogServiceHelper> mockServiceHelper = sp<MockWatchdogServiceHelper>::make();
std::shared_ptr<MockCarWatchdogServiceForSystem> mockService =
SharedRefBase::make<MockCarWatchdogServiceForSystem>();
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<MockWatchdogServiceHelper> mockServiceHelper = sp<MockWatchdogServiceHelper>::make();
std::shared_ptr<MockCarWatchdogServiceForSystem> mockService =
SharedRefBase::make<MockCarWatchdogServiceForSystem>();
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<int>(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());
}
} // namespace watchdog
} // namespace automotive
} // namespace android