1 /*
2 * Copyright (C) 2022 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 "HidlHalPropValue.h"
18 #include "HidlVhalClient.h"
19
20 #include <aidl/android/hardware/automotive/vehicle/StatusCode.h>
21 #include <android-base/result.h>
22 #include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
23 #include <gtest/gtest.h>
24 #include <utils/StrongPointer.h>
25
26 #include <VehicleUtils.h>
27
28 #include <vector>
29
30 namespace android {
31 namespace frameworks {
32 namespace automotive {
33 namespace vhal {
34 namespace hidl_test {
35
36 using ::android::sp;
37 using ::android::hardware::hidl_vec;
38 using ::android::hardware::Return;
39 using ::android::hardware::automotive::vehicle::toInt;
40 using ::android::hardware::automotive::vehicle::V2_0::IVehicle;
41 using ::android::hardware::automotive::vehicle::V2_0::IVehicleCallback;
42 using ::android::hardware::automotive::vehicle::V2_0::StatusCode;
43 using ::android::hardware::automotive::vehicle::V2_0::SubscribeFlags;
44 using ::android::hardware::automotive::vehicle::V2_0::SubscribeOptions;
45 using ::android::hardware::automotive::vehicle::V2_0::VehiclePropConfig;
46 using ::android::hardware::automotive::vehicle::V2_0::VehiclePropValue;
47
48 class MockVhal final : public IVehicle {
49 public:
getAllPropConfigs(IVehicle::getAllPropConfigs_cb callback)50 Return<void> getAllPropConfigs(IVehicle::getAllPropConfigs_cb callback) override {
51 callback(mPropConfigs);
52 return {};
53 }
54
getPropConfigs(const hidl_vec<int32_t> & props,IVehicle::getPropConfigs_cb callback)55 Return<void> getPropConfigs(const hidl_vec<int32_t>& props,
56 IVehicle::getPropConfigs_cb callback) override {
57 mGetPropConfigsProps = props;
58 callback(mStatus, mPropConfigs);
59 return {};
60 }
61
get(const VehiclePropValue & requestPropValue,IVehicle::get_cb callback)62 Return<void> get(const VehiclePropValue& requestPropValue, IVehicle::get_cb callback) override {
63 mRequestPropValue = requestPropValue;
64 callback(mStatus, mPropValue);
65 return {};
66 }
67
set(const VehiclePropValue & value)68 Return<StatusCode> set(const VehiclePropValue& value) override {
69 mRequestPropValue = value;
70 return mStatus;
71 }
72
subscribe(const sp<IVehicleCallback> & callback,const hidl_vec<SubscribeOptions> & options)73 Return<StatusCode> subscribe(const sp<IVehicleCallback>& callback,
74 const hidl_vec<SubscribeOptions>& options) override {
75 mSubscribedCallback = callback;
76 mSubscribeOptions = options;
77 return mStatus;
78 }
79
unsubscribe(const sp<IVehicleCallback> & callback,int32_t propId)80 Return<StatusCode> unsubscribe([[maybe_unused]] const sp<IVehicleCallback>& callback,
81 int32_t propId) override {
82 mUnsubscribedPropId = propId;
83 return mStatus;
84 }
85
debugDump(IVehicle::debugDump_cb callback)86 Return<void> debugDump([[maybe_unused]] IVehicle::debugDump_cb callback) override { return {}; }
87
88 // Test functions
89
setPropConfigs(std::vector<VehiclePropConfig> configs)90 void setPropConfigs(std::vector<VehiclePropConfig> configs) { mPropConfigs = configs; }
91
setStatus(StatusCode status)92 void setStatus(StatusCode status) { mStatus = status; }
93
setVehiclePropValue(VehiclePropValue value)94 void setVehiclePropValue(VehiclePropValue value) { mPropValue = value; }
95
getGetPropConfigsProps()96 std::vector<int32_t> getGetPropConfigsProps() { return mGetPropConfigsProps; }
97
getRequestPropValue()98 VehiclePropValue getRequestPropValue() { return mRequestPropValue; }
99
getSubscribeOptions()100 std::vector<SubscribeOptions> getSubscribeOptions() { return mSubscribeOptions; }
101
getUnsubscribedPropId()102 int32_t getUnsubscribedPropId() { return mUnsubscribedPropId; }
103
triggerOnPropertyEvent(const std::vector<VehiclePropValue> & values)104 void triggerOnPropertyEvent(const std::vector<VehiclePropValue>& values) {
105 mSubscribedCallback->onPropertyEvent(values);
106 }
107
triggerSetErrorEvent(StatusCode status,int32_t propId,int32_t areaId)108 void triggerSetErrorEvent(StatusCode status, int32_t propId, int32_t areaId) {
109 mSubscribedCallback->onPropertySetError(status, propId, areaId);
110 }
111
112 private:
113 std::vector<VehiclePropConfig> mPropConfigs;
114 StatusCode mStatus = StatusCode::OK;
115 VehiclePropValue mPropValue;
116
117 std::vector<int32_t> mGetPropConfigsProps;
118 VehiclePropValue mRequestPropValue;
119 sp<IVehicleCallback> mSubscribedCallback;
120 std::vector<SubscribeOptions> mSubscribeOptions;
121 int32_t mUnsubscribedPropId;
122 };
123
124 class MockSubscriptionCallback final : public ISubscriptionCallback {
125 public:
onPropertyEvent(const std::vector<std::unique_ptr<IHalPropValue>> & values)126 void onPropertyEvent(const std::vector<std::unique_ptr<IHalPropValue>>& values) override {
127 for (const auto& value : values) {
128 mEventPropIds.push_back(value->getPropId());
129 }
130 }
onPropertySetError(const std::vector<HalPropError> & errors)131 void onPropertySetError(const std::vector<HalPropError>& errors) override { mErrors = errors; }
132
getEventPropIds()133 std::vector<int32_t> getEventPropIds() { return mEventPropIds; }
134
getErrors()135 std::vector<HalPropError> getErrors() { return mErrors; }
136
137 private:
138 std::vector<int32_t> mEventPropIds;
139 std::vector<HalPropError> mErrors;
140 };
141
142 class HidlVhalClientTest : public ::testing::Test {
143 protected:
144 constexpr static int32_t TEST_PROP_ID = 1;
145 constexpr static int32_t TEST_AREA_ID = 2;
146 constexpr static int32_t TEST_PROP_ID_2 = 3;
147
148 const VehiclePropValue TEST_VALUE{
149 .prop = TEST_PROP_ID,
150 .areaId = TEST_AREA_ID,
151 .value.int32Values = {1},
152 };
153
SetUp()154 void SetUp() override {
155 mVhal = new MockVhal();
156 mVhalClient = std::make_unique<HidlVhalClient>(mVhal);
157 }
158
getVhal()159 MockVhal* getVhal() { return mVhal.get(); }
160
getClient()161 HidlVhalClient* getClient() { return mVhalClient.get(); }
162
triggerBinderDied()163 void triggerBinderDied() { mVhalClient->onBinderDied(); }
164
165 private:
166 sp<MockVhal> mVhal;
167 std::unique_ptr<HidlVhalClient> mVhalClient;
168 };
169
TEST_F(HidlVhalClientTest,testIsAidl)170 TEST_F(HidlVhalClientTest, testIsAidl) {
171 ASSERT_FALSE(getClient()->isAidlVhal());
172 }
173
TEST_F(HidlVhalClientTest,testGetValue)174 TEST_F(HidlVhalClientTest, testGetValue) {
175 VhalClientResult<std::unique_ptr<IHalPropValue>> result;
176 VhalClientResult<std::unique_ptr<IHalPropValue>>* resultPtr = &result;
177 bool gotResult = false;
178 bool* gotResultPtr = &gotResult;
179 auto callback = std::make_shared<HidlVhalClient::GetValueCallbackFunc>(
180 [resultPtr, gotResultPtr](VhalClientResult<std::unique_ptr<IHalPropValue>> r) {
181 *resultPtr = std::move(r);
182 *gotResultPtr = true;
183 });
184 getVhal()->setVehiclePropValue(TEST_VALUE);
185
186 getClient()->getValue(HidlHalPropValue(TEST_PROP_ID, TEST_AREA_ID), callback);
187
188 ASSERT_TRUE(gotResult);
189 ASSERT_EQ(getVhal()->getRequestPropValue().prop, TEST_PROP_ID);
190 ASSERT_EQ(getVhal()->getRequestPropValue().areaId, TEST_AREA_ID);
191 ASSERT_TRUE(result.ok());
192 auto gotValue = std::move(result.value());
193 ASSERT_EQ(gotValue->getPropId(), TEST_PROP_ID);
194 ASSERT_EQ(gotValue->getAreaId(), TEST_AREA_ID);
195 ASSERT_EQ(gotValue->getInt32Values(), std::vector<int32_t>({1}));
196 }
197
TEST_F(HidlVhalClientTest,testGetValueError)198 TEST_F(HidlVhalClientTest, testGetValueError) {
199 getVhal()->setStatus(StatusCode::INTERNAL_ERROR);
200
201 VhalClientResult<std::unique_ptr<IHalPropValue>> result;
202 VhalClientResult<std::unique_ptr<IHalPropValue>>* resultPtr = &result;
203 bool gotResult = false;
204 bool* gotResultPtr = &gotResult;
205 auto callback = std::make_shared<HidlVhalClient::GetValueCallbackFunc>(
206 [resultPtr, gotResultPtr](VhalClientResult<std::unique_ptr<IHalPropValue>> r) {
207 *resultPtr = std::move(r);
208 *gotResultPtr = true;
209 });
210
211 getClient()->getValue(HidlHalPropValue(TEST_PROP_ID, TEST_AREA_ID), callback);
212
213 ASSERT_TRUE(gotResult);
214 ASSERT_FALSE(result.ok());
215 }
216
TEST_F(HidlVhalClientTest,testSetValue)217 TEST_F(HidlVhalClientTest, testSetValue) {
218 VhalClientResult<void> result;
219 VhalClientResult<void>* resultPtr = &result;
220 bool gotResult = false;
221 bool* gotResultPtr = &gotResult;
222 auto callback = std::make_shared<HidlVhalClient::SetValueCallbackFunc>(
223 [resultPtr, gotResultPtr](VhalClientResult<void> r) {
224 *resultPtr = std::move(r);
225 *gotResultPtr = true;
226 });
227
228 getClient()->setValue(HidlHalPropValue(TEST_PROP_ID, TEST_AREA_ID), callback);
229
230 ASSERT_TRUE(gotResult);
231 ASSERT_EQ(getVhal()->getRequestPropValue().prop, TEST_PROP_ID);
232 ASSERT_EQ(getVhal()->getRequestPropValue().areaId, TEST_AREA_ID);
233 ASSERT_TRUE(result.ok());
234 }
TEST_F(HidlVhalClientTest,testSetValueError)235 TEST_F(HidlVhalClientTest, testSetValueError) {
236 getVhal()->setStatus(StatusCode::INTERNAL_ERROR);
237
238 VhalClientResult<void> result;
239 VhalClientResult<void>* resultPtr = &result;
240 bool gotResult = false;
241 bool* gotResultPtr = &gotResult;
242 auto callback = std::make_shared<HidlVhalClient::SetValueCallbackFunc>(
243 [resultPtr, gotResultPtr](VhalClientResult<void> r) {
244 *resultPtr = std::move(r);
245 *gotResultPtr = true;
246 });
247
248 getClient()->setValue(HidlHalPropValue(TEST_PROP_ID, TEST_AREA_ID), callback);
249
250 ASSERT_TRUE(gotResult);
251 ASSERT_FALSE(result.ok());
252 }
253
TEST_F(HidlVhalClientTest,testAddOnBinderDiedCallback)254 TEST_F(HidlVhalClientTest, testAddOnBinderDiedCallback) {
255 struct Result {
256 bool callbackOneCalled = false;
257 bool callbackTwoCalled = false;
258 } result;
259
260 getClient()->addOnBinderDiedCallback(std::make_shared<HidlVhalClient::OnBinderDiedCallbackFunc>(
261 [&result] { result.callbackOneCalled = true; }));
262 getClient()->addOnBinderDiedCallback(std::make_shared<HidlVhalClient::OnBinderDiedCallbackFunc>(
263 [&result] { result.callbackTwoCalled = true; }));
264 triggerBinderDied();
265
266 ASSERT_TRUE(result.callbackOneCalled);
267 ASSERT_TRUE(result.callbackTwoCalled);
268 }
269
TEST_F(HidlVhalClientTest,testRemoveOnBinderDiedCallback)270 TEST_F(HidlVhalClientTest, testRemoveOnBinderDiedCallback) {
271 struct Result {
272 bool callbackOneCalled = false;
273 bool callbackTwoCalled = false;
274 } result;
275
276 auto callbackOne = std::make_shared<HidlVhalClient::OnBinderDiedCallbackFunc>(
277 [&result] { result.callbackOneCalled = true; });
278 auto callbackTwo = std::make_shared<HidlVhalClient::OnBinderDiedCallbackFunc>(
279 [&result] { result.callbackTwoCalled = true; });
280 getClient()->addOnBinderDiedCallback(callbackOne);
281 getClient()->addOnBinderDiedCallback(callbackTwo);
282 getClient()->removeOnBinderDiedCallback(callbackOne);
283 triggerBinderDied();
284
285 ASSERT_FALSE(result.callbackOneCalled);
286 ASSERT_TRUE(result.callbackTwoCalled);
287 }
288
TEST_F(HidlVhalClientTest,testGetAllPropConfigs)289 TEST_F(HidlVhalClientTest, testGetAllPropConfigs) {
290 getVhal()->setPropConfigs({
291 VehiclePropConfig{
292 .prop = TEST_PROP_ID,
293 .areaConfigs = {{
294 .areaId = TEST_AREA_ID,
295 .minInt32Value = 0,
296 .maxInt32Value = 1,
297 }},
298 },
299 VehiclePropConfig{
300 .prop = TEST_PROP_ID_2,
301 },
302 });
303
304 auto result = getClient()->getAllPropConfigs();
305
306 ASSERT_TRUE(result.ok());
307 std::vector<std::unique_ptr<IHalPropConfig>> configs = std::move(result.value());
308
309 ASSERT_EQ(configs.size(), static_cast<size_t>(2));
310 ASSERT_EQ(configs[0]->getPropId(), TEST_PROP_ID);
311 ASSERT_EQ(configs[0]->getAreaConfigSize(), static_cast<size_t>(1));
312
313 const IHalAreaConfig* areaConfig = configs[0]->getAreaConfigs();
314 ASSERT_EQ(areaConfig->getAreaId(), TEST_AREA_ID);
315 ASSERT_EQ(areaConfig->getMinInt32Value(), 0);
316 ASSERT_EQ(areaConfig->getMaxInt32Value(), 1);
317
318 ASSERT_EQ(configs[1]->getPropId(), TEST_PROP_ID_2);
319 ASSERT_EQ(configs[1]->getAreaConfigSize(), static_cast<size_t>(0));
320 }
321
TEST_F(HidlVhalClientTest,testGetPropConfigs)322 TEST_F(HidlVhalClientTest, testGetPropConfigs) {
323 getVhal()->setPropConfigs({
324 VehiclePropConfig{
325 .prop = TEST_PROP_ID,
326 .areaConfigs = {{
327 .areaId = TEST_AREA_ID,
328 .minInt32Value = 0,
329 .maxInt32Value = 1,
330 }},
331 },
332 VehiclePropConfig{
333 .prop = TEST_PROP_ID_2,
334 },
335 });
336
337 std::vector<int32_t> propIds = {TEST_PROP_ID, TEST_PROP_ID_2};
338 auto result = getClient()->getPropConfigs(propIds);
339
340 ASSERT_EQ(getVhal()->getGetPropConfigsProps(), propIds);
341 ASSERT_TRUE(result.ok());
342 std::vector<std::unique_ptr<IHalPropConfig>> configs = std::move(result.value());
343
344 ASSERT_EQ(configs.size(), static_cast<size_t>(2));
345 ASSERT_EQ(configs[0]->getPropId(), TEST_PROP_ID);
346 ASSERT_EQ(configs[0]->getAreaConfigSize(), static_cast<size_t>(1));
347
348 const IHalAreaConfig* areaConfig = configs[0]->getAreaConfigs();
349 ASSERT_EQ(areaConfig->getAreaId(), TEST_AREA_ID);
350 ASSERT_EQ(areaConfig->getMinInt32Value(), 0);
351 ASSERT_EQ(areaConfig->getMaxInt32Value(), 1);
352
353 ASSERT_EQ(configs[1]->getPropId(), TEST_PROP_ID_2);
354 ASSERT_EQ(configs[1]->getAreaConfigSize(), static_cast<size_t>(0));
355 }
356
TEST_F(HidlVhalClientTest,testGetPropConfigsError)357 TEST_F(HidlVhalClientTest, testGetPropConfigsError) {
358 getVhal()->setStatus(StatusCode::INTERNAL_ERROR);
359
360 std::vector<int32_t> propIds = {TEST_PROP_ID, TEST_PROP_ID_2};
361 auto result = getClient()->getPropConfigs(propIds);
362
363 ASSERT_FALSE(result.ok());
364 }
365
TEST_F(HidlVhalClientTest,testSubscribe)366 TEST_F(HidlVhalClientTest, testSubscribe) {
367 std::vector<::aidl::android::hardware::automotive::vehicle::SubscribeOptions> options = {
368 {
369 .propId = TEST_PROP_ID,
370 .areaIds = {TEST_AREA_ID},
371 .sampleRate = 1.0,
372 },
373 {
374 .propId = TEST_PROP_ID_2,
375 .sampleRate = 2.0,
376 },
377 };
378 std::vector<SubscribeOptions> hidlOptions = {
379 {
380 .propId = TEST_PROP_ID,
381 .flags = SubscribeFlags::EVENTS_FROM_CAR,
382 .sampleRate = 1.0,
383 },
384 {
385 .propId = TEST_PROP_ID_2,
386 .flags = SubscribeFlags::EVENTS_FROM_CAR,
387 .sampleRate = 2.0,
388 },
389 };
390
391 auto callback = std::make_shared<MockSubscriptionCallback>();
392 auto subscriptionClient = getClient()->getSubscriptionClient(callback);
393 auto result = subscriptionClient->subscribe(options);
394
395 ASSERT_TRUE(result.ok());
396 ASSERT_EQ(getVhal()->getSubscribeOptions(), hidlOptions);
397
398 getVhal()->triggerOnPropertyEvent(std::vector<VehiclePropValue>{
399 {
400 .prop = TEST_PROP_ID,
401 .areaId = TEST_AREA_ID,
402 .value.int32Values = {1},
403 },
404 });
405
406 ASSERT_EQ(callback->getEventPropIds(), std::vector<int32_t>({TEST_PROP_ID}));
407
408 getVhal()->triggerSetErrorEvent(StatusCode::INTERNAL_ERROR, TEST_PROP_ID, TEST_AREA_ID);
409
410 auto errors = callback->getErrors();
411 ASSERT_EQ(errors.size(), static_cast<size_t>(1));
412 ASSERT_EQ(errors[0].propId, TEST_PROP_ID);
413 ASSERT_EQ(errors[0].areaId, TEST_AREA_ID);
414 ASSERT_EQ(errors[0].status,
415 ::aidl::android::hardware::automotive::vehicle::StatusCode::INTERNAL_ERROR);
416 }
417
TEST_F(HidlVhalClientTest,testSubscribeError)418 TEST_F(HidlVhalClientTest, testSubscribeError) {
419 std::vector<::aidl::android::hardware::automotive::vehicle::SubscribeOptions> options = {
420 {
421 .propId = TEST_PROP_ID,
422 .areaIds = {TEST_AREA_ID},
423 .sampleRate = 1.0,
424 },
425 {
426 .propId = TEST_PROP_ID_2,
427 .sampleRate = 2.0,
428 },
429 };
430
431 getVhal()->setStatus(StatusCode::INTERNAL_ERROR);
432 auto callback = std::make_shared<MockSubscriptionCallback>();
433 auto subscriptionClient = getClient()->getSubscriptionClient(callback);
434 auto result = subscriptionClient->subscribe(options);
435
436 ASSERT_FALSE(result.ok());
437 }
438
TEST_F(HidlVhalClientTest,testUnubscribe)439 TEST_F(HidlVhalClientTest, testUnubscribe) {
440 auto callback = std::make_shared<MockSubscriptionCallback>();
441 auto subscriptionClient = getClient()->getSubscriptionClient(callback);
442 auto result = subscriptionClient->unsubscribe({TEST_PROP_ID});
443
444 ASSERT_TRUE(result.ok());
445 ASSERT_EQ(getVhal()->getUnsubscribedPropId(), TEST_PROP_ID);
446 }
447
TEST_F(HidlVhalClientTest,testUnubscribeError)448 TEST_F(HidlVhalClientTest, testUnubscribeError) {
449 getVhal()->setStatus(StatusCode::INTERNAL_ERROR);
450 auto callback = std::make_shared<MockSubscriptionCallback>();
451 auto subscriptionClient = getClient()->getSubscriptionClient(callback);
452 auto result = subscriptionClient->unsubscribe({TEST_PROP_ID});
453
454 ASSERT_FALSE(result.ok());
455 }
456
457 } // namespace hidl_test
458 } // namespace vhal
459 } // namespace automotive
460 } // namespace frameworks
461 } // namespace android
462