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