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 <aidl/android/hardware/automotive/vehicle/BnVehicle.h>
18 #include <android/binder_ibinder.h>
19 #include <gtest/gtest.h>
20
21 #include <AidlHalPropValue.h>
22 #include <AidlVhalClient.h>
23 #include <VehicleHalTypes.h>
24 #include <VehicleUtils.h>
25
26 #include <atomic>
27 #include <condition_variable> // NOLINT
28 #include <mutex> // NOLINT
29 #include <thread> // NOLINT
30
31 namespace android {
32 namespace frameworks {
33 namespace automotive {
34 namespace vhal {
35 namespace aidl_test {
36
37 using ::android::hardware::automotive::vehicle::toInt;
38
39 using ::aidl::android::hardware::automotive::vehicle::BnVehicle;
40 using ::aidl::android::hardware::automotive::vehicle::GetValueRequest;
41 using ::aidl::android::hardware::automotive::vehicle::GetValueRequests;
42 using ::aidl::android::hardware::automotive::vehicle::GetValueResult;
43 using ::aidl::android::hardware::automotive::vehicle::GetValueResults;
44 using ::aidl::android::hardware::automotive::vehicle::IVehicle;
45 using ::aidl::android::hardware::automotive::vehicle::IVehicleCallback;
46 using ::aidl::android::hardware::automotive::vehicle::RawPropValues;
47 using ::aidl::android::hardware::automotive::vehicle::SetValueRequest;
48 using ::aidl::android::hardware::automotive::vehicle::SetValueRequests;
49 using ::aidl::android::hardware::automotive::vehicle::SetValueResult;
50 using ::aidl::android::hardware::automotive::vehicle::SetValueResults;
51 using ::aidl::android::hardware::automotive::vehicle::StatusCode;
52 using ::aidl::android::hardware::automotive::vehicle::SubscribeOptions;
53 using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
54 using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfigs;
55 using ::aidl::android::hardware::automotive::vehicle::VehiclePropError;
56 using ::aidl::android::hardware::automotive::vehicle::VehiclePropErrors;
57 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
58 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValues;
59
60 using ::ndk::ScopedAStatus;
61 using ::ndk::SharedRefBase;
62
63 class MockVhal final : public BnVehicle {
64 public:
65 using CallbackType = std::shared_ptr<IVehicleCallback>;
66
~MockVhal()67 ~MockVhal() {
68 std::unique_lock<std::mutex> lk(mLock);
69 mCv.wait_for(lk, std::chrono::milliseconds(1000), [this] { return mThreadCount == 0; });
70 }
71
getAllPropConfigs(VehiclePropConfigs * returnConfigs)72 ScopedAStatus getAllPropConfigs(VehiclePropConfigs* returnConfigs) override {
73 if (mStatus != StatusCode::OK) {
74 return ScopedAStatus::fromServiceSpecificError(toInt(mStatus));
75 }
76
77 returnConfigs->payloads = mPropConfigs;
78 return ScopedAStatus::ok();
79 }
80
getValues(const CallbackType & callback,const GetValueRequests & requests)81 ScopedAStatus getValues(const CallbackType& callback,
82 const GetValueRequests& requests) override {
83 mGetValueRequests = requests.payloads;
84
85 if (mStatus != StatusCode::OK) {
86 return ScopedAStatus::fromServiceSpecificError(toInt(mStatus));
87 }
88
89 if (mWaitTimeInMs == 0) {
90 callback->onGetValues(GetValueResults{.payloads = mGetValueResults});
91 } else {
92 mThreadCount++;
93 std::thread t([this, callback]() {
94 std::this_thread::sleep_for(std::chrono::milliseconds(mWaitTimeInMs));
95 callback->onGetValues(GetValueResults{.payloads = mGetValueResults});
96 mThreadCount--;
97 mCv.notify_one();
98 });
99 // Detach the thread here so we do not have to maintain the thread object. mThreadCount
100 // and mCv make sure we wait for all threads to end before we exit.
101 t.detach();
102 }
103 return ScopedAStatus::ok();
104 }
105
setValues(const CallbackType & callback,const SetValueRequests & requests)106 ScopedAStatus setValues(const CallbackType& callback,
107 const SetValueRequests& requests) override {
108 mSetValueRequests = requests.payloads;
109
110 if (mStatus != StatusCode::OK) {
111 return ScopedAStatus::fromServiceSpecificError(toInt(mStatus));
112 }
113
114 if (mWaitTimeInMs == 0) {
115 callback->onSetValues(SetValueResults{.payloads = mSetValueResults});
116 } else {
117 mThreadCount++;
118 std::thread t([this, callback]() {
119 std::this_thread::sleep_for(std::chrono::milliseconds(mWaitTimeInMs));
120 callback->onSetValues(SetValueResults{.payloads = mSetValueResults});
121 mThreadCount--;
122 mCv.notify_one();
123 });
124 // Detach the thread here so we do not have to maintain the thread object. mThreadCount
125 // and mCv make sure we wait for all threads to end before we exit.
126 t.detach();
127 }
128 return ScopedAStatus::ok();
129 }
130
getPropConfigs(const std::vector<int32_t> & props,VehiclePropConfigs * returnConfigs)131 ScopedAStatus getPropConfigs(const std::vector<int32_t>& props,
132 VehiclePropConfigs* returnConfigs) override {
133 mGetPropConfigPropIds = props;
134 if (mStatus != StatusCode::OK) {
135 return ScopedAStatus::fromServiceSpecificError(toInt(mStatus));
136 }
137
138 returnConfigs->payloads = mPropConfigs;
139 return ScopedAStatus::ok();
140 }
141
subscribe(const CallbackType & callback,const std::vector<SubscribeOptions> & options,int32_t maxSharedMemoryFileCount)142 ScopedAStatus subscribe(const CallbackType& callback,
143 const std::vector<SubscribeOptions>& options,
144 [[maybe_unused]] int32_t maxSharedMemoryFileCount) override {
145 mSubscriptionCallback = callback;
146 mSubscriptionOptions = options;
147
148 if (mStatus != StatusCode::OK) {
149 return ScopedAStatus::fromServiceSpecificError(toInt(mStatus));
150 }
151 return ScopedAStatus::ok();
152 }
153
unsubscribe(const CallbackType & callback,const std::vector<int32_t> & propIds)154 ScopedAStatus unsubscribe([[maybe_unused]] const CallbackType& callback,
155 const std::vector<int32_t>& propIds) override {
156 mUnsubscribePropIds = propIds;
157
158 if (mStatus != StatusCode::OK) {
159 return ScopedAStatus::fromServiceSpecificError(toInt(mStatus));
160 }
161 return ScopedAStatus::ok();
162 }
163
returnSharedMemory(const CallbackType & callback,int64_t sharedMemoryId)164 ScopedAStatus returnSharedMemory([[maybe_unused]] const CallbackType& callback,
165 [[maybe_unused]] int64_t sharedMemoryId) override {
166 return ScopedAStatus::ok();
167 }
168
169 // Test Functions
170
setGetValueResults(std::vector<GetValueResult> results)171 void setGetValueResults(std::vector<GetValueResult> results) { mGetValueResults = results; }
172
getGetValueRequests()173 std::vector<GetValueRequest> getGetValueRequests() { return mGetValueRequests; }
174
setSetValueResults(std::vector<SetValueResult> results)175 void setSetValueResults(std::vector<SetValueResult> results) { mSetValueResults = results; }
176
getSetValueRequests()177 std::vector<SetValueRequest> getSetValueRequests() { return mSetValueRequests; }
178
setWaitTimeInMs(int64_t waitTimeInMs)179 void setWaitTimeInMs(int64_t waitTimeInMs) { mWaitTimeInMs = waitTimeInMs; }
180
setStatus(StatusCode status)181 void setStatus(StatusCode status) { mStatus = status; }
182
setPropConfigs(std::vector<VehiclePropConfig> configs)183 void setPropConfigs(std::vector<VehiclePropConfig> configs) { mPropConfigs = configs; }
184
getGetPropConfigPropIds()185 std::vector<int32_t> getGetPropConfigPropIds() { return mGetPropConfigPropIds; }
186
getSubscriptionOptions()187 std::vector<SubscribeOptions> getSubscriptionOptions() { return mSubscriptionOptions; }
188
triggerOnPropertyEvent(const std::vector<VehiclePropValue> & values)189 void triggerOnPropertyEvent(const std::vector<VehiclePropValue>& values) {
190 VehiclePropValues propValues = {
191 .payloads = values,
192 };
193 mSubscriptionCallback->onPropertyEvent(propValues, /*sharedMemoryCount=*/0);
194 }
195
triggerSetErrorEvent(const std::vector<VehiclePropError> & errors)196 void triggerSetErrorEvent(const std::vector<VehiclePropError>& errors) {
197 VehiclePropErrors propErrors = {
198 .payloads = errors,
199 };
200 mSubscriptionCallback->onPropertySetError(propErrors);
201 }
202
getUnsubscribedPropIds()203 std::vector<int32_t> getUnsubscribedPropIds() { return mUnsubscribePropIds; }
204
205 private:
206 std::mutex mLock;
207 std::vector<GetValueResult> mGetValueResults;
208 std::vector<GetValueRequest> mGetValueRequests;
209 std::vector<SetValueResult> mSetValueResults;
210 std::vector<SetValueRequest> mSetValueRequests;
211 std::vector<VehiclePropConfig> mPropConfigs;
212 std::vector<int32_t> mGetPropConfigPropIds;
213 int64_t mWaitTimeInMs = 0;
214 StatusCode mStatus = StatusCode::OK;
215 std::condition_variable mCv;
216 std::atomic<int> mThreadCount = 0;
217 CallbackType mSubscriptionCallback;
218 std::vector<SubscribeOptions> mSubscriptionOptions;
219 std::vector<int32_t> mUnsubscribePropIds;
220 };
221
222 class MockSubscriptionCallback : public ISubscriptionCallback {
223 public:
onPropertyEvent(const std::vector<std::unique_ptr<IHalPropValue>> & values)224 void onPropertyEvent(const std::vector<std::unique_ptr<IHalPropValue>>& values) override {
225 for (const auto& value : values) {
226 mEventPropIds.push_back(value->getPropId());
227 }
228 }
onPropertySetError(const std::vector<HalPropError> & errors)229 void onPropertySetError(const std::vector<HalPropError>& errors) override { mErrors = errors; }
230
getEventPropIds()231 std::vector<int32_t> getEventPropIds() { return mEventPropIds; }
232
getErrors()233 std::vector<HalPropError> getErrors() { return mErrors; }
234
235 private:
236 std::vector<int32_t> mEventPropIds;
237 std::vector<HalPropError> mErrors;
238 };
239
240 class AidlVhalClientTest : public ::testing::Test {
241 protected:
242 class TestLinkUnlinkImpl final : public AidlVhalClient::ILinkUnlinkToDeath {
243 public:
linkToDeath(AIBinder * binder,AIBinder_DeathRecipient * recipient,void * cookie)244 binder_status_t linkToDeath([[maybe_unused]] AIBinder* binder,
245 [[maybe_unused]] AIBinder_DeathRecipient* recipient,
246 void* cookie) override {
247 mCookie = cookie;
248 return STATUS_OK;
249 }
250
unlinkToDeath(AIBinder *,AIBinder_DeathRecipient *,void *)251 binder_status_t unlinkToDeath(AIBinder*, AIBinder_DeathRecipient*, void*) override {
252 // DO nothing.
253 return STATUS_OK;
254 }
255
getCookie()256 void* getCookie() { return mCookie; }
257
258 private:
259 void* mCookie;
260 };
261
262 constexpr static int32_t TEST_PROP_ID = 1;
263 constexpr static int32_t TEST_AREA_ID = 2;
264 constexpr static int32_t TEST_PROP_ID_2 = 3;
265 constexpr static int64_t TEST_TIMEOUT_IN_MS = 100;
266
SetUp()267 void SetUp() override {
268 mVhal = SharedRefBase::make<MockVhal>();
269 auto impl = std::make_unique<TestLinkUnlinkImpl>();
270 // We are sure impl would be alive when we use mLinkUnlinkImpl.
271 mLinkUnlinkImpl = impl.get();
272 mVhalClient = std::unique_ptr<AidlVhalClient>(
273 new AidlVhalClient(mVhal, TEST_TIMEOUT_IN_MS, std::move(impl)));
274 }
275
getClient()276 AidlVhalClient* getClient() { return mVhalClient.get(); }
277
getVhal()278 MockVhal* getVhal() { return mVhal.get(); }
279
triggerBinderDied()280 void triggerBinderDied() { AidlVhalClient::onBinderDied(mLinkUnlinkImpl->getCookie()); }
281
triggerBinderUnlinked()282 void triggerBinderUnlinked() { AidlVhalClient::onBinderUnlinked(mLinkUnlinkImpl->getCookie()); }
283
countOnBinderDiedCallbacks()284 size_t countOnBinderDiedCallbacks() { return mVhalClient->countOnBinderDiedCallbacks(); }
285
286 private:
287 std::shared_ptr<MockVhal> mVhal;
288 std::unique_ptr<AidlVhalClient> mVhalClient;
289 TestLinkUnlinkImpl* mLinkUnlinkImpl;
290 };
291
TEST_F(AidlVhalClientTest,testIsAidl)292 TEST_F(AidlVhalClientTest, testIsAidl) {
293 ASSERT_TRUE(getClient()->isAidlVhal());
294 }
295
TEST_F(AidlVhalClientTest,testGetValueNormal)296 TEST_F(AidlVhalClientTest, testGetValueNormal) {
297 VehiclePropValue testProp{
298 .prop = TEST_PROP_ID,
299 .areaId = TEST_AREA_ID,
300 };
301 getVhal()->setWaitTimeInMs(10);
302 getVhal()->setGetValueResults({
303 GetValueResult{
304 .requestId = 0,
305 .status = StatusCode::OK,
306 .prop =
307 VehiclePropValue{
308 .prop = TEST_PROP_ID,
309 .areaId = TEST_AREA_ID,
310 .value =
311 RawPropValues{
312 .int32Values = {1},
313 },
314 },
315 },
316 });
317
318 AidlHalPropValue propValue(TEST_PROP_ID, TEST_AREA_ID);
319 std::mutex lock;
320 std::condition_variable cv;
321 VhalClientResult<std::unique_ptr<IHalPropValue>> result;
322 VhalClientResult<std::unique_ptr<IHalPropValue>>* resultPtr = &result;
323 bool gotResult = false;
324 bool* gotResultPtr = &gotResult;
325
326 auto callback = std::make_shared<AidlVhalClient::GetValueCallbackFunc>(
327 [&lock, &cv, resultPtr,
328 gotResultPtr](VhalClientResult<std::unique_ptr<IHalPropValue>> r) {
329 {
330 std::lock_guard<std::mutex> lockGuard(lock);
331 *resultPtr = std::move(r);
332 *gotResultPtr = true;
333 }
334 cv.notify_one();
335 });
336 getClient()->getValue(propValue, callback);
337
338 std::unique_lock<std::mutex> lk(lock);
339 cv.wait_for(lk, std::chrono::milliseconds(1000), [&gotResult] { return gotResult; });
340
341 ASSERT_TRUE(gotResult);
342 ASSERT_EQ(getVhal()->getGetValueRequests(),
343 std::vector<GetValueRequest>({GetValueRequest{.requestId = 0, .prop = testProp}}));
344 ASSERT_TRUE(result.ok());
345 auto gotValue = std::move(result.value());
346 ASSERT_EQ(gotValue->getPropId(), TEST_PROP_ID);
347 ASSERT_EQ(gotValue->getAreaId(), TEST_AREA_ID);
348 ASSERT_EQ(gotValue->getInt32Values(), std::vector<int32_t>({1}));
349 }
350
TEST_F(AidlVhalClientTest,testGetValueSync)351 TEST_F(AidlVhalClientTest, testGetValueSync) {
352 VehiclePropValue testProp{
353 .prop = TEST_PROP_ID,
354 .areaId = TEST_AREA_ID,
355 };
356 getVhal()->setWaitTimeInMs(10);
357 getVhal()->setGetValueResults({
358 GetValueResult{
359 .requestId = 0,
360 .status = StatusCode::OK,
361 .prop =
362 VehiclePropValue{
363 .prop = TEST_PROP_ID,
364 .areaId = TEST_AREA_ID,
365 .value =
366 RawPropValues{
367 .int32Values = {1},
368 },
369 },
370 },
371 });
372
373 AidlHalPropValue propValue(TEST_PROP_ID, TEST_AREA_ID);
374 VhalClientResult<std::unique_ptr<IHalPropValue>> result = getClient()->getValueSync(propValue);
375
376 ASSERT_EQ(getVhal()->getGetValueRequests(),
377 std::vector<GetValueRequest>({GetValueRequest{.requestId = 0, .prop = testProp}}));
378 ASSERT_TRUE(result.ok());
379 auto gotValue = std::move(result.value());
380 ASSERT_EQ(gotValue->getPropId(), TEST_PROP_ID);
381 ASSERT_EQ(gotValue->getAreaId(), TEST_AREA_ID);
382 ASSERT_EQ(gotValue->getInt32Values(), std::vector<int32_t>({1}));
383 }
384
TEST_F(AidlVhalClientTest,testGetValueTimeout)385 TEST_F(AidlVhalClientTest, testGetValueTimeout) {
386 VehiclePropValue testProp{
387 .prop = TEST_PROP_ID,
388 .areaId = TEST_AREA_ID,
389 };
390 // The request will time-out before the response.
391 getVhal()->setWaitTimeInMs(200);
392 getVhal()->setGetValueResults({
393 GetValueResult{
394 .requestId = 0,
395 .status = StatusCode::OK,
396 .prop =
397 VehiclePropValue{
398 .prop = TEST_PROP_ID,
399 .areaId = TEST_AREA_ID,
400 .value =
401 RawPropValues{
402 .int32Values = {1},
403 },
404 },
405 },
406 });
407
408 AidlHalPropValue propValue(TEST_PROP_ID, TEST_AREA_ID);
409 std::mutex lock;
410 std::condition_variable cv;
411 VhalClientResult<std::unique_ptr<IHalPropValue>> result;
412 VhalClientResult<std::unique_ptr<IHalPropValue>>* resultPtr = &result;
413 bool gotResult = false;
414 bool* gotResultPtr = &gotResult;
415
416 auto callback = std::make_shared<AidlVhalClient::GetValueCallbackFunc>(
417 [&lock, &cv, resultPtr,
418 gotResultPtr](VhalClientResult<std::unique_ptr<IHalPropValue>> r) {
419 {
420 std::lock_guard<std::mutex> lockGuard(lock);
421 *resultPtr = std::move(r);
422 *gotResultPtr = true;
423 }
424 cv.notify_one();
425 });
426 getClient()->getValue(propValue, callback);
427
428 std::unique_lock<std::mutex> lk(lock);
429 cv.wait_for(lk, std::chrono::milliseconds(1000), [&gotResult] { return gotResult; });
430
431 ASSERT_TRUE(gotResult);
432 ASSERT_EQ(getVhal()->getGetValueRequests(),
433 std::vector<GetValueRequest>({GetValueRequest{.requestId = 0, .prop = testProp}}));
434 ASSERT_FALSE(result.ok());
435 ASSERT_EQ(result.error().code(), ErrorCode::TIMEOUT);
436 }
437
TEST_F(AidlVhalClientTest,testGetValueErrorStatus)438 TEST_F(AidlVhalClientTest, testGetValueErrorStatus) {
439 VehiclePropValue testProp{
440 .prop = TEST_PROP_ID,
441 .areaId = TEST_AREA_ID,
442 };
443 getVhal()->setStatus(StatusCode::INTERNAL_ERROR);
444
445 AidlHalPropValue propValue(TEST_PROP_ID, TEST_AREA_ID);
446 VhalClientResult<std::unique_ptr<IHalPropValue>> result;
447 VhalClientResult<std::unique_ptr<IHalPropValue>>* resultPtr = &result;
448
449 getClient()->getValue(propValue,
450 std::make_shared<AidlVhalClient::GetValueCallbackFunc>(
451 [resultPtr](VhalClientResult<std::unique_ptr<IHalPropValue>> r) {
452 *resultPtr = std::move(r);
453 }));
454
455 ASSERT_EQ(getVhal()->getGetValueRequests(),
456 std::vector<GetValueRequest>({GetValueRequest{.requestId = 0, .prop = testProp}}));
457 ASSERT_FALSE(result.ok());
458 ASSERT_EQ(result.error().code(), ErrorCode::INTERNAL_ERROR_FROM_VHAL);
459 }
460
TEST_F(AidlVhalClientTest,testGetValueNonOkayResult)461 TEST_F(AidlVhalClientTest, testGetValueNonOkayResult) {
462 VehiclePropValue testProp{
463 .prop = TEST_PROP_ID,
464 .areaId = TEST_AREA_ID,
465 };
466 getVhal()->setGetValueResults({
467 GetValueResult{
468 .requestId = 0,
469 .status = StatusCode::INTERNAL_ERROR,
470 },
471 });
472
473 AidlHalPropValue propValue(TEST_PROP_ID, TEST_AREA_ID);
474 VhalClientResult<std::unique_ptr<IHalPropValue>> result;
475 VhalClientResult<std::unique_ptr<IHalPropValue>>* resultPtr = &result;
476
477 getClient()->getValue(propValue,
478 std::make_shared<AidlVhalClient::GetValueCallbackFunc>(
479 [resultPtr](VhalClientResult<std::unique_ptr<IHalPropValue>> r) {
480 *resultPtr = std::move(r);
481 }));
482
483 ASSERT_EQ(getVhal()->getGetValueRequests(),
484 std::vector<GetValueRequest>({GetValueRequest{.requestId = 0, .prop = testProp}}));
485 ASSERT_FALSE(result.ok());
486 ASSERT_EQ(result.error().code(), ErrorCode::INTERNAL_ERROR_FROM_VHAL);
487 }
488
TEST_F(AidlVhalClientTest,testGetValueIgnoreInvalidRequestId)489 TEST_F(AidlVhalClientTest, testGetValueIgnoreInvalidRequestId) {
490 VehiclePropValue testProp{
491 .prop = TEST_PROP_ID,
492 .areaId = TEST_AREA_ID,
493 };
494 getVhal()->setGetValueResults({
495 GetValueResult{
496 .requestId = 0,
497 .status = StatusCode::OK,
498 .prop =
499 VehiclePropValue{
500 .prop = TEST_PROP_ID,
501 .areaId = TEST_AREA_ID,
502 .value =
503 RawPropValues{
504 .int32Values = {1},
505 },
506 },
507 },
508 // This result has invalid request ID and should be ignored.
509 GetValueResult{
510 .requestId = 1,
511 .status = StatusCode::INTERNAL_ERROR,
512 },
513 });
514
515 AidlHalPropValue propValue(TEST_PROP_ID, TEST_AREA_ID);
516 VhalClientResult<std::unique_ptr<IHalPropValue>> result;
517 VhalClientResult<std::unique_ptr<IHalPropValue>>* resultPtr = &result;
518
519 getClient()->getValue(propValue,
520 std::make_shared<AidlVhalClient::GetValueCallbackFunc>(
521 [resultPtr](VhalClientResult<std::unique_ptr<IHalPropValue>> r) {
522 *resultPtr = std::move(r);
523 }));
524
525 ASSERT_EQ(getVhal()->getGetValueRequests(),
526 std::vector<GetValueRequest>({GetValueRequest{.requestId = 0, .prop = testProp}}));
527 ASSERT_TRUE(result.ok());
528 auto gotValue = std::move(result.value());
529 ASSERT_EQ(gotValue->getPropId(), TEST_PROP_ID);
530 ASSERT_EQ(gotValue->getAreaId(), TEST_AREA_ID);
531 ASSERT_EQ(gotValue->getInt32Values(), std::vector<int32_t>({1}));
532 }
533
TEST_F(AidlVhalClientTest,testSetValueNormal)534 TEST_F(AidlVhalClientTest, testSetValueNormal) {
535 VehiclePropValue testProp{
536 .prop = TEST_PROP_ID,
537 .areaId = TEST_AREA_ID,
538 };
539 getVhal()->setWaitTimeInMs(10);
540 getVhal()->setSetValueResults({
541 SetValueResult{
542 .requestId = 0,
543 .status = StatusCode::OK,
544 },
545 });
546
547 AidlHalPropValue propValue(TEST_PROP_ID, TEST_AREA_ID);
548 std::mutex lock;
549 std::condition_variable cv;
550 VhalClientResult<void> result;
551 VhalClientResult<void>* resultPtr = &result;
552 bool gotResult = false;
553 bool* gotResultPtr = &gotResult;
554
555 auto callback = std::make_shared<AidlVhalClient::SetValueCallbackFunc>(
556 [&lock, &cv, resultPtr, gotResultPtr](VhalClientResult<void> r) {
557 {
558 std::lock_guard<std::mutex> lockGuard(lock);
559 *resultPtr = std::move(r);
560 *gotResultPtr = true;
561 }
562 cv.notify_one();
563 });
564 getClient()->setValue(propValue, callback);
565
566 std::unique_lock<std::mutex> lk(lock);
567 cv.wait_for(lk, std::chrono::milliseconds(1000), [&gotResult] { return gotResult; });
568
569 ASSERT_TRUE(gotResult);
570 ASSERT_EQ(getVhal()->getSetValueRequests(),
571 std::vector<SetValueRequest>({SetValueRequest{.requestId = 0, .value = testProp}}));
572 ASSERT_TRUE(result.ok());
573 }
574
TEST_F(AidlVhalClientTest,testSetValueSync)575 TEST_F(AidlVhalClientTest, testSetValueSync) {
576 VehiclePropValue testProp{
577 .prop = TEST_PROP_ID,
578 .areaId = TEST_AREA_ID,
579 };
580 getVhal()->setWaitTimeInMs(10);
581 getVhal()->setSetValueResults({
582 SetValueResult{
583 .requestId = 0,
584 .status = StatusCode::OK,
585 },
586 });
587
588 AidlHalPropValue propValue(TEST_PROP_ID, TEST_AREA_ID);
589 VhalClientResult<void> result = getClient()->setValueSync(propValue);
590
591 ASSERT_EQ(getVhal()->getSetValueRequests(),
592 std::vector<SetValueRequest>({SetValueRequest{.requestId = 0, .value = testProp}}));
593 ASSERT_TRUE(result.ok());
594 }
595
TEST_F(AidlVhalClientTest,testSetValueTimeout)596 TEST_F(AidlVhalClientTest, testSetValueTimeout) {
597 VehiclePropValue testProp{
598 .prop = TEST_PROP_ID,
599 .areaId = TEST_AREA_ID,
600 };
601 // The request will time-out before the response.
602 getVhal()->setWaitTimeInMs(200);
603 getVhal()->setSetValueResults({
604 SetValueResult{
605 .requestId = 0,
606 .status = StatusCode::OK,
607 },
608 });
609
610 AidlHalPropValue propValue(TEST_PROP_ID, TEST_AREA_ID);
611 std::mutex lock;
612 std::condition_variable cv;
613 VhalClientResult<void> result;
614 VhalClientResult<void>* resultPtr = &result;
615 bool gotResult = false;
616 bool* gotResultPtr = &gotResult;
617
618 auto callback = std::make_shared<AidlVhalClient::SetValueCallbackFunc>(
619 [&lock, &cv, resultPtr, gotResultPtr](VhalClientResult<void> r) {
620 {
621 std::lock_guard<std::mutex> lockGuard(lock);
622 *resultPtr = std::move(r);
623 *gotResultPtr = true;
624 }
625 cv.notify_one();
626 });
627 getClient()->setValue(propValue, callback);
628
629 std::unique_lock<std::mutex> lk(lock);
630 cv.wait_for(lk, std::chrono::milliseconds(1000), [&gotResult] { return gotResult; });
631
632 ASSERT_TRUE(gotResult);
633 ASSERT_EQ(getVhal()->getSetValueRequests(),
634 std::vector<SetValueRequest>({SetValueRequest{.requestId = 0, .value = testProp}}));
635 ASSERT_FALSE(result.ok());
636 ASSERT_EQ(result.error().code(), ErrorCode::TIMEOUT);
637 }
638
TEST_F(AidlVhalClientTest,testSetValueErrorStatus)639 TEST_F(AidlVhalClientTest, testSetValueErrorStatus) {
640 VehiclePropValue testProp{
641 .prop = TEST_PROP_ID,
642 .areaId = TEST_AREA_ID,
643 };
644 getVhal()->setStatus(StatusCode::INTERNAL_ERROR);
645
646 AidlHalPropValue propValue(TEST_PROP_ID, TEST_AREA_ID);
647 VhalClientResult<void> result;
648 VhalClientResult<void>* resultPtr = &result;
649
650 getClient()->setValue(propValue,
651 std::make_shared<AidlVhalClient::SetValueCallbackFunc>(
652 [resultPtr](VhalClientResult<void> r) {
653 *resultPtr = std::move(r);
654 }));
655
656 ASSERT_EQ(getVhal()->getSetValueRequests(),
657 std::vector<SetValueRequest>({SetValueRequest{.requestId = 0, .value = testProp}}));
658 ASSERT_FALSE(result.ok());
659 ASSERT_EQ(result.error().code(), ErrorCode::INTERNAL_ERROR_FROM_VHAL);
660 }
661
TEST_F(AidlVhalClientTest,testSetValueNonOkayResult)662 TEST_F(AidlVhalClientTest, testSetValueNonOkayResult) {
663 VehiclePropValue testProp{
664 .prop = TEST_PROP_ID,
665 .areaId = TEST_AREA_ID,
666 };
667 getVhal()->setSetValueResults({
668 SetValueResult{
669 .requestId = 0,
670 .status = StatusCode::INTERNAL_ERROR,
671 },
672 });
673
674 AidlHalPropValue propValue(TEST_PROP_ID, TEST_AREA_ID);
675 VhalClientResult<void> result;
676 VhalClientResult<void>* resultPtr = &result;
677
678 getClient()->setValue(propValue,
679 std::make_shared<AidlVhalClient::SetValueCallbackFunc>(
680 [resultPtr](VhalClientResult<void> r) {
681 *resultPtr = std::move(r);
682 }));
683
684 ASSERT_EQ(getVhal()->getSetValueRequests(),
685 std::vector<SetValueRequest>({SetValueRequest{.requestId = 0, .value = testProp}}));
686 ASSERT_FALSE(result.ok());
687 ASSERT_EQ(result.error().code(), ErrorCode::INTERNAL_ERROR_FROM_VHAL);
688 }
689
TEST_F(AidlVhalClientTest,testSetValueIgnoreInvalidRequestId)690 TEST_F(AidlVhalClientTest, testSetValueIgnoreInvalidRequestId) {
691 VehiclePropValue testProp{
692 .prop = TEST_PROP_ID,
693 .areaId = TEST_AREA_ID,
694 };
695 getVhal()->setSetValueResults({
696 SetValueResult{
697 .requestId = 0,
698 .status = StatusCode::OK,
699 },
700 // This result has invalid request ID and should be ignored.
701 SetValueResult{
702 .requestId = 1,
703 .status = StatusCode::INTERNAL_ERROR,
704 },
705 });
706
707 AidlHalPropValue propValue(TEST_PROP_ID, TEST_AREA_ID);
708 VhalClientResult<void> result;
709 VhalClientResult<void>* resultPtr = &result;
710
711 getClient()->setValue(propValue,
712 std::make_shared<AidlVhalClient::SetValueCallbackFunc>(
713 [resultPtr](VhalClientResult<void> r) {
714 *resultPtr = std::move(r);
715 }));
716
717 ASSERT_EQ(getVhal()->getSetValueRequests(),
718 std::vector<SetValueRequest>({SetValueRequest{.requestId = 0, .value = testProp}}));
719 ASSERT_TRUE(result.ok());
720 }
721
TEST_F(AidlVhalClientTest,testAddOnBinderDiedCallback)722 TEST_F(AidlVhalClientTest, testAddOnBinderDiedCallback) {
723 struct Result {
724 bool callbackOneCalled = false;
725 bool callbackTwoCalled = false;
726 } result;
727
728 getClient()->addOnBinderDiedCallback(std::make_shared<AidlVhalClient::OnBinderDiedCallbackFunc>(
729 [&result] { result.callbackOneCalled = true; }));
730 getClient()->addOnBinderDiedCallback(std::make_shared<AidlVhalClient::OnBinderDiedCallbackFunc>(
731 [&result] { result.callbackTwoCalled = true; }));
732 triggerBinderDied();
733
734 ASSERT_TRUE(result.callbackOneCalled);
735 ASSERT_TRUE(result.callbackTwoCalled);
736
737 triggerBinderUnlinked();
738
739 ASSERT_EQ(countOnBinderDiedCallbacks(), static_cast<size_t>(0));
740 }
741
TEST_F(AidlVhalClientTest,testRemoveOnBinderDiedCallback)742 TEST_F(AidlVhalClientTest, testRemoveOnBinderDiedCallback) {
743 struct Result {
744 bool callbackOneCalled = false;
745 bool callbackTwoCalled = false;
746 } result;
747
748 auto callbackOne = std::make_shared<AidlVhalClient::OnBinderDiedCallbackFunc>(
749 [&result] { result.callbackOneCalled = true; });
750 auto callbackTwo = std::make_shared<AidlVhalClient::OnBinderDiedCallbackFunc>(
751 [&result] { result.callbackTwoCalled = true; });
752 getClient()->addOnBinderDiedCallback(callbackOne);
753 getClient()->addOnBinderDiedCallback(callbackTwo);
754 getClient()->removeOnBinderDiedCallback(callbackOne);
755 triggerBinderDied();
756
757 ASSERT_FALSE(result.callbackOneCalled);
758 ASSERT_TRUE(result.callbackTwoCalled);
759
760 triggerBinderUnlinked();
761
762 ASSERT_EQ(countOnBinderDiedCallbacks(), static_cast<size_t>(0));
763 }
764
TEST_F(AidlVhalClientTest,testGetAllPropConfigs)765 TEST_F(AidlVhalClientTest, testGetAllPropConfigs) {
766 getVhal()->setPropConfigs({
767 VehiclePropConfig{
768 .prop = TEST_PROP_ID,
769 .areaConfigs = {{
770 .areaId = TEST_AREA_ID,
771 .minInt32Value = 0,
772 .maxInt32Value = 1,
773 }},
774 },
775 VehiclePropConfig{
776 .prop = TEST_PROP_ID_2,
777 },
778 });
779
780 auto result = getClient()->getAllPropConfigs();
781
782 ASSERT_TRUE(result.ok());
783 std::vector<std::unique_ptr<IHalPropConfig>> configs = std::move(result.value());
784
785 ASSERT_EQ(configs.size(), static_cast<size_t>(2));
786 ASSERT_EQ(configs[0]->getPropId(), TEST_PROP_ID);
787 ASSERT_EQ(configs[0]->getAreaConfigSize(), static_cast<size_t>(1));
788
789 const IHalAreaConfig* areaConfig = configs[0]->getAreaConfigs();
790 ASSERT_EQ(areaConfig->getAreaId(), TEST_AREA_ID);
791 ASSERT_EQ(areaConfig->getMinInt32Value(), 0);
792 ASSERT_EQ(areaConfig->getMaxInt32Value(), 1);
793
794 ASSERT_EQ(configs[1]->getPropId(), TEST_PROP_ID_2);
795 ASSERT_EQ(configs[1]->getAreaConfigSize(), static_cast<size_t>(0));
796 }
797
TEST_F(AidlVhalClientTest,testGetAllPropConfigsError)798 TEST_F(AidlVhalClientTest, testGetAllPropConfigsError) {
799 getVhal()->setStatus(StatusCode::INTERNAL_ERROR);
800
801 auto result = getClient()->getAllPropConfigs();
802
803 ASSERT_FALSE(result.ok());
804 ASSERT_EQ(result.error().code(), ErrorCode::INTERNAL_ERROR_FROM_VHAL);
805 }
806
TEST_F(AidlVhalClientTest,testGetPropConfigs)807 TEST_F(AidlVhalClientTest, testGetPropConfigs) {
808 getVhal()->setPropConfigs({
809 VehiclePropConfig{
810 .prop = TEST_PROP_ID,
811 .areaConfigs = {{
812 .areaId = TEST_AREA_ID,
813 .minInt32Value = 0,
814 .maxInt32Value = 1,
815 }},
816 },
817 VehiclePropConfig{
818 .prop = TEST_PROP_ID_2,
819 },
820 });
821
822 std::vector<int32_t> propIds = {TEST_PROP_ID, TEST_PROP_ID_2};
823 auto result = getClient()->getPropConfigs(propIds);
824
825 ASSERT_EQ(getVhal()->getGetPropConfigPropIds(), propIds);
826 ASSERT_TRUE(result.ok());
827 std::vector<std::unique_ptr<IHalPropConfig>> configs = std::move(result.value());
828
829 ASSERT_EQ(configs.size(), static_cast<size_t>(2));
830 ASSERT_EQ(configs[0]->getPropId(), TEST_PROP_ID);
831 ASSERT_EQ(configs[0]->getAreaConfigSize(), static_cast<size_t>(1));
832
833 const IHalAreaConfig* areaConfig = configs[0]->getAreaConfigs();
834 ASSERT_EQ(areaConfig->getAreaId(), TEST_AREA_ID);
835 ASSERT_EQ(areaConfig->getMinInt32Value(), 0);
836 ASSERT_EQ(areaConfig->getMaxInt32Value(), 1);
837
838 ASSERT_EQ(configs[1]->getPropId(), TEST_PROP_ID_2);
839 ASSERT_EQ(configs[1]->getAreaConfigSize(), static_cast<size_t>(0));
840 }
841
TEST_F(AidlVhalClientTest,testGetPropConfigsError)842 TEST_F(AidlVhalClientTest, testGetPropConfigsError) {
843 getVhal()->setStatus(StatusCode::INTERNAL_ERROR);
844
845 std::vector<int32_t> propIds = {TEST_PROP_ID, TEST_PROP_ID_2};
846 auto result = getClient()->getPropConfigs(propIds);
847
848 ASSERT_FALSE(result.ok());
849 }
850
TEST_F(AidlVhalClientTest,testSubscribe)851 TEST_F(AidlVhalClientTest, testSubscribe) {
852 std::vector<SubscribeOptions> options = {
853 {
854 .propId = TEST_PROP_ID,
855 .areaIds = {TEST_AREA_ID},
856 .sampleRate = 1.0,
857 },
858 {
859 .propId = TEST_PROP_ID_2,
860 .sampleRate = 2.0,
861 },
862 };
863
864 auto callback = std::make_shared<MockSubscriptionCallback>();
865 auto subscriptionClient = getClient()->getSubscriptionClient(callback);
866 auto result = subscriptionClient->subscribe(options);
867
868 ASSERT_TRUE(result.ok());
869 ASSERT_EQ(getVhal()->getSubscriptionOptions(), options);
870
871 getVhal()->triggerOnPropertyEvent(std::vector<VehiclePropValue>{
872 {
873 .prop = TEST_PROP_ID,
874 .areaId = TEST_AREA_ID,
875 .value.int32Values = {1},
876 },
877 });
878
879 ASSERT_EQ(callback->getEventPropIds(), std::vector<int32_t>({TEST_PROP_ID}));
880
881 getVhal()->triggerSetErrorEvent(std::vector<VehiclePropError>({
882 {
883 .propId = TEST_PROP_ID,
884 .areaId = TEST_AREA_ID,
885 .errorCode = StatusCode::INTERNAL_ERROR,
886 },
887 }));
888
889 auto errors = callback->getErrors();
890 ASSERT_EQ(errors.size(), static_cast<size_t>(1));
891 ASSERT_EQ(errors[0].propId, TEST_PROP_ID);
892 ASSERT_EQ(errors[0].areaId, TEST_AREA_ID);
893 ASSERT_EQ(errors[0].status, StatusCode::INTERNAL_ERROR);
894 }
895
TEST_F(AidlVhalClientTest,testSubscribeError)896 TEST_F(AidlVhalClientTest, testSubscribeError) {
897 std::vector<SubscribeOptions> options = {
898 {
899 .propId = TEST_PROP_ID,
900 .areaIds = {TEST_AREA_ID},
901 .sampleRate = 1.0,
902 },
903 {
904 .propId = TEST_PROP_ID_2,
905 .sampleRate = 2.0,
906 },
907 };
908
909 getVhal()->setStatus(StatusCode::INTERNAL_ERROR);
910 auto callback = std::make_shared<MockSubscriptionCallback>();
911 auto subscriptionClient = getClient()->getSubscriptionClient(callback);
912 auto result = subscriptionClient->subscribe(options);
913
914 ASSERT_FALSE(result.ok());
915 }
916
TEST_F(AidlVhalClientTest,testUnubscribe)917 TEST_F(AidlVhalClientTest, testUnubscribe) {
918 auto callback = std::make_shared<MockSubscriptionCallback>();
919 auto subscriptionClient = getClient()->getSubscriptionClient(callback);
920 auto result = subscriptionClient->unsubscribe({TEST_PROP_ID});
921
922 ASSERT_TRUE(result.ok());
923 ASSERT_EQ(getVhal()->getUnsubscribedPropIds(), std::vector<int32_t>({TEST_PROP_ID}));
924 }
925
TEST_F(AidlVhalClientTest,testUnubscribeError)926 TEST_F(AidlVhalClientTest, testUnubscribeError) {
927 getVhal()->setStatus(StatusCode::INTERNAL_ERROR);
928 auto callback = std::make_shared<MockSubscriptionCallback>();
929 auto subscriptionClient = getClient()->getSubscriptionClient(callback);
930 auto result = subscriptionClient->unsubscribe({TEST_PROP_ID});
931
932 ASSERT_FALSE(result.ok());
933 }
934
935 } // namespace aidl_test
936 } // namespace vhal
937 } // namespace automotive
938 } // namespace frameworks
939 } // namespace android
940