1 /*
2 * Copyright (C) 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <aidl/Gtest.h>
18 #include <aidl/Vintf.h>
19 #include <aidl/android/automotive/watchdog/BnCarWatchdogClient.h>
20 #include <aidl/android/automotive/watchdog/BnResourceOveruseListener.h>
21 #include <aidl/android/automotive/watchdog/ICarWatchdog.h>
22 #include <aidl/android/automotive/watchdog/ResourceOveruseStats.h>
23 #include <aidl/android/automotive/watchdog/ResourceType.h>
24 #include <android-base/chrono_utils.h>
25 #include <android-base/properties.h>
26 #include <android/binder_manager.h>
27 #include <android/binder_process.h>
28 #include <gmock/gmock.h>
29 #include <utils/Condition.h>
30 #include <utils/Mutex.h>
31
32 #include <unistd.h>
33
34 #include <future> // NOLINT(build/c++11)
35
36 using ::aidl::android::automotive::watchdog::BnCarWatchdogClient;
37 using ::aidl::android::automotive::watchdog::BnResourceOveruseListener;
38 using ::aidl::android::automotive::watchdog::ICarWatchdog;
39 using ::aidl::android::automotive::watchdog::ResourceOveruseStats;
40 using ::aidl::android::automotive::watchdog::ResourceType;
41 using ::aidl::android::automotive::watchdog::TimeoutLength;
42 using ::android::Condition;
43 using ::android::Mutex;
44 using ::android::OK;
45 using ::ndk::ScopedAStatus;
46 using ::ndk::SharedRefBase;
47 using ::testing::_;
48 using ::testing::InitGoogleTest;
49 using ::testing::Invoke;
50 using ::testing::Return;
51 using ::testing::TestWithParam;
52 using ::testing::ValuesIn;
53
54 namespace {
55
isInQemu()56 bool isInQemu() {
57 return android::base::GetBoolProperty("ro.boot.qemu", false) ||
58 android::base::GetBoolProperty("ro.kernel.qemu", false);
59 }
60
61 // Emulators run on QEMU and tend to have significant worse performance than physical devices.
62 // In order for emulators to be as test compliant as possible, 15s wait time is used instead of the
63 // 6s to account for the emulator's poor performance.
64 const std::chrono::nanoseconds kMaxWatchdogPingWaitTimeNs = isInQemu() ? 15s : 6s;
65
66 class MockCarWatchdogClient : public BnCarWatchdogClient {
67 public:
MockCarWatchdogClient()68 MockCarWatchdogClient() {}
69
70 MOCK_METHOD(ScopedAStatus, checkIfAlive, (int32_t, TimeoutLength), (override));
71 MOCK_METHOD(ScopedAStatus, prepareProcessTermination, (), (override));
72
expectCheckIfAlive()73 void expectCheckIfAlive() {
74 EXPECT_CALL(*this, checkIfAlive(_, _))
75 .WillOnce(Invoke(
76 [&](int32_t sessionId, TimeoutLength timeoutLength) -> ScopedAStatus {
77 Mutex::Autolock lock(mMutex);
78 mSessionId = sessionId;
79 mTimeoutLength = timeoutLength;
80 mCond.signal();
81 return ScopedAStatus::ok();
82 }));
83 }
84
waitCheckIfAlive(TimeoutLength expectedTimeoutLength,int32_t * actualSessionId)85 void waitCheckIfAlive(TimeoutLength expectedTimeoutLength, int32_t* actualSessionId) {
86 Mutex::Autolock lock(mMutex);
87 ASSERT_THAT(mCond.waitRelative(mMutex, kMaxWatchdogPingWaitTimeNs.count()), OK);
88 ASSERT_THAT(mTimeoutLength, expectedTimeoutLength);
89 *actualSessionId = mSessionId;
90 }
91
92 private:
93 Mutex mMutex;
94 Condition mCond GUARDED_BY(mMutex);
95 int32_t mSessionId GUARDED_BY(mMutex);
96 TimeoutLength mTimeoutLength GUARDED_BY(mMutex);
97 };
98
99 class MockResourceOveruseListener : public BnResourceOveruseListener {
100 public:
MockResourceOveruseListener()101 MockResourceOveruseListener() {}
~MockResourceOveruseListener()102 ~MockResourceOveruseListener() {}
103
104 MOCK_METHOD(ndk::ScopedAStatus, onOveruse,
105 (const aidl::android::automotive::watchdog::ResourceOveruseStats&), (override));
106 };
107
108 } // namespace
109
110 class WatchdogAidlTest : public TestWithParam<std::string> {
111 public:
SetUp()112 void SetUp() override {
113 watchdogServer = ICarWatchdog::fromBinder(
114 ndk::SpAIBinder(AServiceManager_waitForService(GetParam().c_str())));
115 ASSERT_NE(watchdogServer.get(), nullptr);
116 }
117
118 std::shared_ptr<ICarWatchdog> watchdogServer;
119 };
120
TEST_P(WatchdogAidlTest,TestWatchdogClient)121 TEST_P(WatchdogAidlTest, TestWatchdogClient) {
122 std::shared_ptr<MockCarWatchdogClient> mockClient =
123 SharedRefBase::make<MockCarWatchdogClient>();
124 mockClient->expectCheckIfAlive();
125 ScopedAStatus status =
126 watchdogServer->registerClient(mockClient, TimeoutLength::TIMEOUT_CRITICAL);
127 ASSERT_TRUE(status.isOk()) << "Failed to register client: " << status.getMessage();
128 int32_t sessionId;
129 ASSERT_NO_FATAL_FAILURE(
130 mockClient->waitCheckIfAlive(TimeoutLength::TIMEOUT_CRITICAL, &sessionId));
131 status = watchdogServer->tellClientAlive(mockClient, sessionId);
132 ASSERT_TRUE(status.isOk()) << "Failed to tell client alive: " << status.getMessage();
133 status = watchdogServer->unregisterClient(mockClient);
134 ASSERT_TRUE(status.isOk()) << "Failed to unregister client: " << status.getMessage();
135 }
136
TEST_P(WatchdogAidlTest,TestFailsRegisterClientWithNullptrClient)137 TEST_P(WatchdogAidlTest, TestFailsRegisterClientWithNullptrClient) {
138 ASSERT_FALSE(watchdogServer->registerClient(nullptr, TimeoutLength::TIMEOUT_CRITICAL).isOk())
139 << "Should fail to register null client";
140 }
141
TEST_P(WatchdogAidlTest,TestFailsToTellClientAliveForNotRegisteredClient)142 TEST_P(WatchdogAidlTest, TestFailsToTellClientAliveForNotRegisteredClient) {
143 std::shared_ptr<MockCarWatchdogClient> mockClient =
144 SharedRefBase::make<MockCarWatchdogClient>();
145 ASSERT_FALSE(watchdogServer->tellClientAlive(mockClient, 0).isOk())
146 << "Should fail tell client alive for not registered client";
147 }
148
TEST_P(WatchdogAidlTest,TestFailsToUnRegisterNotRegisteredClient)149 TEST_P(WatchdogAidlTest, TestFailsToUnRegisterNotRegisteredClient) {
150 std::shared_ptr<MockCarWatchdogClient> mockClient =
151 SharedRefBase::make<MockCarWatchdogClient>();
152 ASSERT_FALSE(watchdogServer->unregisterClient(mockClient).isOk())
153 << "Should fail to unregister not registered client";
154 }
155
TEST_P(WatchdogAidlTest,TestResourceOveruseListener)156 TEST_P(WatchdogAidlTest, TestResourceOveruseListener) {
157 std::shared_ptr<MockResourceOveruseListener> mockListener =
158 SharedRefBase::make<MockResourceOveruseListener>();
159 ScopedAStatus status =
160 watchdogServer->addResourceOveruseListener({ResourceType::IO}, mockListener);
161 ASSERT_TRUE(status.isOk()) << "Failed to add resource overuse listener: "
162 << status.getMessage();
163 status = watchdogServer->removeResourceOveruseListener(mockListener);
164 ASSERT_TRUE(status.isOk()) << "Failed to remove resource overuse listener: "
165 << status.getMessage();
166 }
167
TEST_P(WatchdogAidlTest,TestFailsAddResourceOveruseListenerWithNoResourceType)168 TEST_P(WatchdogAidlTest, TestFailsAddResourceOveruseListenerWithNoResourceType) {
169 std::shared_ptr<MockResourceOveruseListener> mockListener =
170 SharedRefBase::make<MockResourceOveruseListener>();
171 ASSERT_FALSE(watchdogServer->addResourceOveruseListener({}, mockListener).isOk())
172 << "Should fail to add resource overuse listener with no resource type";
173 }
174
TEST_P(WatchdogAidlTest,TestFailsAddResourceOveruseListenerWithNullptrListener)175 TEST_P(WatchdogAidlTest, TestFailsAddResourceOveruseListenerWithNullptrListener) {
176 ASSERT_FALSE(watchdogServer->addResourceOveruseListener({ResourceType::IO}, nullptr).isOk())
177 << "Should fail to add null resource overuse listener";
178 }
179
TEST_P(WatchdogAidlTest,TestFailsToRemoveNotAddedResourceOveruseListener)180 TEST_P(WatchdogAidlTest, TestFailsToRemoveNotAddedResourceOveruseListener) {
181 std::shared_ptr<MockResourceOveruseListener> mockListener =
182 SharedRefBase::make<MockResourceOveruseListener>();
183 ASSERT_FALSE(watchdogServer->removeResourceOveruseListener(mockListener).isOk())
184 << "Should fail to remote listener that is not added";
185 }
186
187 /*
188 * getResourceOveruseStats AIDL method is not tested as it requires writing to disk and waiting
189 * until the watchdog server has read I/O stats. The waiting duration depends on the watchdog
190 * server's performance data collection frequency, which varies between 20 - 60 seconds depending
191 * on the build type. The core implementation is tested in ATS with the help of custom performance
192 * data collection, which requires dumpsys access and this is not available to VTS. Thus skipping
193 * this test in VTS.
194 */
195
TEST_P(WatchdogAidlTest,TestFailsGetResourceOveruseStatsWithNoResourceTypes)196 TEST_P(WatchdogAidlTest, TestFailsGetResourceOveruseStatsWithNoResourceTypes) {
197 std::vector<ResourceOveruseStats> resourceOveruseStats;
198 ASSERT_FALSE(watchdogServer->getResourceOveruseStats({}, &resourceOveruseStats).isOk())
199 << "Should fail to fetch resource overuse stats with no resource types";
200 }
201
202 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WatchdogAidlTest);
203 INSTANTIATE_TEST_SUITE_P(CarWatchdogServer, WatchdogAidlTest,
204 ValuesIn(android::getAidlHalInstanceNames(ICarWatchdog::descriptor)),
205 android::PrintInstanceNameToString);
206
main(int argc,char ** argv)207 int main(int argc, char** argv) {
208 InitGoogleTest(&argc, argv);
209 ABinderProcess_setThreadPoolMaxThreadCount(1);
210 ABinderProcess_startThreadPool();
211 return RUN_ALL_TESTS();
212 }
213