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