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 "ConnectedClient.h"
18 #include "DefaultVehicleHal.h"
19 #include "MockVehicleCallback.h"
20 #include "MockVehicleHardware.h"
21
22 #include <IVehicleHardware.h>
23 #include <LargeParcelableBase.h>
24 #include <aidl/android/hardware/automotive/vehicle/IVehicle.h>
25 #include <aidl/android/hardware/automotive/vehicle/IVehicleCallback.h>
26
27 #include <android-base/thread_annotations.h>
28 #include <gmock/gmock.h>
29 #include <gtest/gtest.h>
30 #include <sys/mman.h>
31 #include <utils/Log.h>
32 #include <utils/SystemClock.h>
33
34 #include <chrono>
35 #include <list>
36 #include <memory>
37 #include <mutex>
38 #include <optional>
39 #include <thread>
40 #include <unordered_map>
41 #include <vector>
42
43 namespace android {
44 namespace hardware {
45 namespace automotive {
46 namespace vehicle {
47
48 namespace {
49
50 using ::aidl::android::hardware::automotive::vehicle::GetValueRequest;
51 using ::aidl::android::hardware::automotive::vehicle::GetValueRequests;
52 using ::aidl::android::hardware::automotive::vehicle::GetValueResult;
53 using ::aidl::android::hardware::automotive::vehicle::GetValueResults;
54 using ::aidl::android::hardware::automotive::vehicle::IVehicle;
55 using ::aidl::android::hardware::automotive::vehicle::IVehicleCallback;
56 using ::aidl::android::hardware::automotive::vehicle::SetValueRequest;
57 using ::aidl::android::hardware::automotive::vehicle::SetValueRequests;
58 using ::aidl::android::hardware::automotive::vehicle::SetValueResult;
59 using ::aidl::android::hardware::automotive::vehicle::SetValueResults;
60 using ::aidl::android::hardware::automotive::vehicle::StatusCode;
61 using ::aidl::android::hardware::automotive::vehicle::SubscribeOptions;
62 using ::aidl::android::hardware::automotive::vehicle::VehicleAreaWindow;
63 using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
64 using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfigs;
65 using ::aidl::android::hardware::automotive::vehicle::VehiclePropErrors;
66 using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
67 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyAccess;
68 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyChangeMode;
69 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
70 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValues;
71
72 using ::android::automotive::car_binder_lib::LargeParcelableBase;
73 using ::android::base::Result;
74
75 using ::ndk::ScopedAStatus;
76 using ::ndk::ScopedFileDescriptor;
77 using ::ndk::SpAIBinder;
78
79 using ::testing::ContainsRegex;
80 using ::testing::Eq;
81 using ::testing::UnorderedElementsAre;
82 using ::testing::UnorderedElementsAreArray;
83 using ::testing::WhenSortedBy;
84
85 constexpr int32_t INVALID_PROP_ID = 0;
86 // VehiclePropertyGroup:SYSTEM,VehicleArea:WINDOW,VehiclePropertyType:INT32
87 constexpr int32_t INT32_WINDOW_PROP = 10001 + 0x10000000 + 0x03000000 + 0x00400000;
88 // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
89 constexpr int32_t GLOBAL_ON_CHANGE_PROP = 10002 + 0x10000000 + 0x01000000 + 0x00400000;
90 // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
91 constexpr int32_t GLOBAL_CONTINUOUS_PROP = 10003 + 0x10000000 + 0x01000000 + 0x00400000;
92 // VehiclePropertyGroup:SYSTEM,VehicleArea:WINDOW,VehiclePropertyType:INT32
93 constexpr int32_t AREA_ON_CHANGE_PROP = 10004 + 0x10000000 + 0x03000000 + 0x00400000;
94 // VehiclePropertyGroup:SYSTEM,VehicleArea:WINDOW,VehiclePropertyType:INT32
95 constexpr int32_t AREA_CONTINUOUS_PROP = 10005 + 0x10000000 + 0x03000000 + 0x00400000;
96 // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
97 constexpr int32_t READ_ONLY_PROP = 10006 + 0x10000000 + 0x01000000 + 0x00400000;
98 // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
99 constexpr int32_t WRITE_ONLY_PROP = 10007 + 0x10000000 + 0x01000000 + 0x00400000;
100
testInt32VecProp(size_t i)101 int32_t testInt32VecProp(size_t i) {
102 // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32_VEC
103 return static_cast<int32_t>(i) + 0x10000000 + 0x01000000 + 0x00410000;
104 }
105
106 struct PropConfigCmp {
operator ()android::hardware::automotive::vehicle::__anon350b19a40111::PropConfigCmp107 bool operator()(const VehiclePropConfig& a, const VehiclePropConfig& b) const {
108 return (a.prop < b.prop);
109 }
110 } propConfigCmp;
111
112 struct SetValuesInvalidRequestTestCase {
113 std::string name;
114 VehiclePropValue request;
115 StatusCode expectedStatus;
116 };
117
getSetValuesInvalidRequestTestCases()118 std::vector<SetValuesInvalidRequestTestCase> getSetValuesInvalidRequestTestCases() {
119 return {{
120 .name = "config_not_found",
121 .request =
122 {
123 // No config for INVALID_PROP_ID.
124 .prop = INVALID_PROP_ID,
125 },
126 .expectedStatus = StatusCode::INVALID_ARG,
127 },
128 {
129 .name = "invalid_prop_value",
130 .request =
131 {
132 .prop = testInt32VecProp(0),
133 // No int32Values for INT32_VEC property.
134 .value.int32Values = {},
135 },
136 .expectedStatus = StatusCode::INVALID_ARG,
137 },
138 {
139 .name = "value_out_of_range",
140 .request =
141 {
142 .prop = testInt32VecProp(0),
143 // We configured the range to be 0-100.
144 .value.int32Values = {0, -1},
145 },
146 .expectedStatus = StatusCode::INVALID_ARG,
147 },
148 {
149 .name = "invalid_area",
150 .request =
151 {
152 .prop = INT32_WINDOW_PROP,
153 .value.int32Values = {0},
154 // Only ROW_1_LEFT is allowed.
155 .areaId = toInt(VehicleAreaWindow::ROW_1_RIGHT),
156 },
157 .expectedStatus = StatusCode::INVALID_ARG,
158 },
159 {
160 .name = "no_write_permission",
161 .request =
162 {
163 .prop = READ_ONLY_PROP,
164 .value.int32Values = {0},
165 },
166 .expectedStatus = StatusCode::ACCESS_DENIED,
167 }};
168 }
169
170 struct SubscribeInvalidOptionsTestCase {
171 std::string name;
172 SubscribeOptions option;
173 };
174
getSubscribeInvalidOptionsTestCases()175 std::vector<SubscribeInvalidOptionsTestCase> getSubscribeInvalidOptionsTestCases() {
176 return {{
177 .name = "invalid_prop",
178 .option =
179 {
180 .propId = INVALID_PROP_ID,
181 },
182 },
183 {
184 .name = "invalid_area_ID",
185 .option =
186 {
187 .propId = AREA_ON_CHANGE_PROP,
188 .areaIds = {0},
189 },
190 },
191 {
192 .name = "invalid_sample_rate",
193 .option =
194 {
195 .propId = GLOBAL_CONTINUOUS_PROP,
196 .sampleRate = 0.0,
197 },
198 },
199 {
200 .name = "static_property",
201 .option =
202 {
203 // Default change mode is static.
204 .propId = testInt32VecProp(0),
205 },
206 }};
207 }
208
209 } // namespace
210
211 class DefaultVehicleHalTest : public testing::Test {
212 public:
SetUp()213 void SetUp() override {
214 auto hardware = std::make_unique<MockVehicleHardware>();
215 std::vector<VehiclePropConfig> testConfigs;
216 for (size_t i = 0; i < 10000; i++) {
217 testConfigs.push_back(VehiclePropConfig{
218 .prop = testInt32VecProp(i),
219 .access = VehiclePropertyAccess::READ_WRITE,
220 .areaConfigs =
221 {
222 {
223 .areaId = 0,
224 .minInt32Value = 0,
225 .maxInt32Value = 100,
226 },
227 },
228 });
229 }
230 // A property with area config.
231 testConfigs.push_back(
232 VehiclePropConfig{.prop = INT32_WINDOW_PROP,
233 .access = VehiclePropertyAccess::READ_WRITE,
234 .areaConfigs = {{
235 .areaId = toInt(VehicleAreaWindow::ROW_1_LEFT),
236 .minInt32Value = 0,
237 .maxInt32Value = 100,
238 }}});
239 // A global on-change property.
240 testConfigs.push_back(VehiclePropConfig{
241 .prop = GLOBAL_ON_CHANGE_PROP,
242 .access = VehiclePropertyAccess::READ_WRITE,
243 .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
244 });
245 // A global continuous property.
246 testConfigs.push_back(VehiclePropConfig{
247 .prop = GLOBAL_CONTINUOUS_PROP,
248 .access = VehiclePropertyAccess::READ_WRITE,
249 .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
250 .minSampleRate = 0.0,
251 .maxSampleRate = 100.0,
252 });
253 // A per-area on-change property.
254 testConfigs.push_back(VehiclePropConfig{
255 .prop = AREA_ON_CHANGE_PROP,
256 .access = VehiclePropertyAccess::READ_WRITE,
257 .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
258 .areaConfigs =
259 {
260 {
261
262 .areaId = toInt(VehicleAreaWindow::ROW_1_LEFT),
263 .minInt32Value = 0,
264 .maxInt32Value = 100,
265 },
266 {
267 .areaId = toInt(VehicleAreaWindow::ROW_1_RIGHT),
268 .minInt32Value = 0,
269 .maxInt32Value = 100,
270 },
271 },
272 });
273 // A per-area continuous property.
274 testConfigs.push_back(VehiclePropConfig{
275 .prop = AREA_CONTINUOUS_PROP,
276 .access = VehiclePropertyAccess::READ_WRITE,
277 .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
278 .minSampleRate = 0.0,
279 .maxSampleRate = 1000.0,
280 .areaConfigs =
281 {
282 {
283
284 .areaId = toInt(VehicleAreaWindow::ROW_1_LEFT),
285 .minInt32Value = 0,
286 .maxInt32Value = 100,
287 },
288 {
289 .areaId = toInt(VehicleAreaWindow::ROW_1_RIGHT),
290 .minInt32Value = 0,
291 .maxInt32Value = 100,
292 },
293 },
294 });
295 // A read-only property.
296 testConfigs.push_back(VehiclePropConfig{
297 .prop = READ_ONLY_PROP,
298 .access = VehiclePropertyAccess::READ,
299 .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
300 .minSampleRate = 0.0,
301 .maxSampleRate = 1000.0,
302 });
303 // A write-only property.
304 testConfigs.push_back(VehiclePropConfig{
305 .prop = WRITE_ONLY_PROP,
306 .access = VehiclePropertyAccess::WRITE,
307 .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
308 .minSampleRate = 0.0,
309 .maxSampleRate = 1000.0,
310 });
311 // Register the heartbeat event property.
312 testConfigs.push_back(VehiclePropConfig{
313 .prop = toInt(VehicleProperty::VHAL_HEARTBEAT),
314 .access = VehiclePropertyAccess::READ,
315 .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
316 });
317 hardware->setPropertyConfigs(testConfigs);
318 mHardwarePtr = hardware.get();
319 mVhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
320 mVhalClient = IVehicle::fromBinder(mVhal->asBinder());
321 mCallback = ndk::SharedRefBase::make<MockVehicleCallback>();
322 // Keep the local binder alive.
323 mBinder = mCallback->asBinder();
324 mCallbackClient = IVehicleCallback::fromBinder(mBinder);
325
326 // Set the linkToDeath to a fake implementation that always returns OK.
327 auto binderImpl = std::make_unique<TestBinderImpl>();
328 mBinderImpl = binderImpl.get();
329 mVhal->setBinderImpl(std::move(binderImpl));
330 }
331
TearDown()332 void TearDown() override {
333 ASSERT_EQ(countPendingRequests(), static_cast<size_t>(0))
334 << "must have no pending requests when test finishes";
335 }
336
getHardware()337 MockVehicleHardware* getHardware() { return mHardwarePtr; }
338
getClient()339 std::shared_ptr<IVehicle> getClient() { return mVhal; }
340
getCallbackClient()341 std::shared_ptr<IVehicleCallback> getCallbackClient() { return mCallbackClient; }
342
getCallback()343 MockVehicleCallback* getCallback() { return mCallback.get(); }
344
setTimeout(int64_t timeoutInNano)345 void setTimeout(int64_t timeoutInNano) { mVhal->setTimeout(timeoutInNano); }
346
countPendingRequests()347 size_t countPendingRequests() { return mVhal->mPendingRequestPool->countPendingRequests(); }
348
countClients()349 size_t countClients() {
350 std::scoped_lock<std::mutex> lockGuard(mVhal->mLock);
351 return mVhal->mGetValuesClients.size() + mVhal->mSetValuesClients.size() +
352 mVhal->mSubscriptionClients->countClients();
353 }
354
getPool()355 std::shared_ptr<PendingRequestPool> getPool() { return mVhal->mPendingRequestPool; }
356
onBinderDied(void * cookie)357 void onBinderDied(void* cookie) { return mVhal->onBinderDied(cookie); }
358
onBinderUnlinked(void * cookie)359 void onBinderUnlinked(void* cookie) { return mVhal->onBinderUnlinked(cookie); }
360
getOnBinderDiedContexts(AIBinder * clientId)361 void* getOnBinderDiedContexts(AIBinder* clientId) {
362 std::scoped_lock<std::mutex> lockGuard(mVhal->mLock);
363 return mVhal->mOnBinderDiedContexts[clientId].get();
364 }
365
countOnBinderDiedContexts()366 size_t countOnBinderDiedContexts() {
367 std::scoped_lock<std::mutex> lockGuard(mVhal->mLock);
368 return mVhal->mOnBinderDiedContexts.size();
369 }
370
hasNoSubscriptions()371 bool hasNoSubscriptions() { return mVhal->mSubscriptionManager->isEmpty(); }
372
setBinderAlive(bool isAlive)373 void setBinderAlive(bool isAlive) { mBinderImpl->setAlive(isAlive); };
374
getValuesTestCases(size_t size,GetValueRequests & requests,std::vector<GetValueResult> & expectedResults,std::vector<GetValueRequest> & expectedHardwareRequests)375 static Result<void> getValuesTestCases(size_t size, GetValueRequests& requests,
376 std::vector<GetValueResult>& expectedResults,
377 std::vector<GetValueRequest>& expectedHardwareRequests) {
378 expectedHardwareRequests.clear();
379 for (size_t i = 0; i < size; i++) {
380 int64_t requestId = static_cast<int64_t>(i);
381 int32_t propId = testInt32VecProp(i);
382 expectedHardwareRequests.push_back(GetValueRequest{
383 .prop =
384 VehiclePropValue{
385 .prop = propId,
386 },
387 .requestId = requestId,
388 });
389 expectedResults.push_back(GetValueResult{
390 .requestId = requestId,
391 .status = StatusCode::OK,
392 .prop =
393 VehiclePropValue{
394 .prop = propId,
395 .value.int32Values = {1, 2, 3, 4},
396 },
397 });
398 }
399
400 requests.payloads = expectedHardwareRequests;
401 auto result = LargeParcelableBase::parcelableToStableLargeParcelable(requests);
402 if (!result.ok()) {
403 return result.error();
404 }
405 if (result.value() != nullptr) {
406 requests.sharedMemoryFd = std::move(*result.value());
407 requests.payloads.clear();
408 }
409 return {};
410 }
411
setValuesTestCases(size_t size,SetValueRequests & requests,std::vector<SetValueResult> & expectedResults,std::vector<SetValueRequest> & expectedHardwareRequests)412 static Result<void> setValuesTestCases(size_t size, SetValueRequests& requests,
413 std::vector<SetValueResult>& expectedResults,
414 std::vector<SetValueRequest>& expectedHardwareRequests) {
415 expectedHardwareRequests.clear();
416 for (size_t i = 0; i < size; i++) {
417 int64_t requestId = static_cast<int64_t>(i);
418 int32_t propId = testInt32VecProp(i);
419 expectedHardwareRequests.push_back(SetValueRequest{
420 .value =
421 VehiclePropValue{
422 .prop = propId,
423 .value.int32Values = {1, 2, 3, 4},
424 },
425 .requestId = requestId,
426 });
427 expectedResults.push_back(SetValueResult{
428 .requestId = requestId,
429 .status = StatusCode::OK,
430 });
431 }
432
433 requests.payloads = expectedHardwareRequests;
434 auto result = LargeParcelableBase::parcelableToStableLargeParcelable(requests);
435 if (!result.ok()) {
436 return result.error();
437 }
438 if (result.value() != nullptr) {
439 requests.payloads.clear();
440 requests.sharedMemoryFd = std::move(*result.value());
441 requests.payloads.clear();
442 }
443 return {};
444 }
445
446 private:
447 class TestBinderImpl final : public DefaultVehicleHal::IBinder {
448 public:
linkToDeath(AIBinder *,AIBinder_DeathRecipient *,void *)449 binder_status_t linkToDeath(AIBinder*, AIBinder_DeathRecipient*, void*) override {
450 if (mIsAlive) {
451 return STATUS_OK;
452 } else {
453 return STATUS_FAILED_TRANSACTION;
454 }
455 }
456
isAlive(const AIBinder *)457 bool isAlive(const AIBinder*) override { return mIsAlive; }
458
setAlive(bool isAlive)459 void setAlive(bool isAlive) { mIsAlive = isAlive; }
460
461 private:
462 bool mIsAlive = true;
463 };
464
465 std::shared_ptr<DefaultVehicleHal> mVhal;
466 std::shared_ptr<IVehicle> mVhalClient;
467 MockVehicleHardware* mHardwarePtr;
468 std::shared_ptr<MockVehicleCallback> mCallback;
469 std::shared_ptr<IVehicleCallback> mCallbackClient;
470 SpAIBinder mBinder;
471 TestBinderImpl* mBinderImpl;
472 };
473
TEST_F(DefaultVehicleHalTest,testGetAllPropConfigsSmall)474 TEST_F(DefaultVehicleHalTest, testGetAllPropConfigsSmall) {
475 auto testConfigs = std::vector<VehiclePropConfig>({
476 VehiclePropConfig{
477 .prop = 1,
478 },
479 VehiclePropConfig{
480 .prop = 2,
481 },
482 });
483
484 auto hardware = std::make_unique<MockVehicleHardware>();
485 hardware->setPropertyConfigs(testConfigs);
486 auto vhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
487 std::shared_ptr<IVehicle> client = IVehicle::fromBinder(vhal->asBinder());
488
489 VehiclePropConfigs output;
490 auto status = client->getAllPropConfigs(&output);
491
492 ASSERT_TRUE(status.isOk()) << "getAllPropConfigs failed: " << status.getMessage();
493 ASSERT_THAT(output.payloads, WhenSortedBy(propConfigCmp, Eq(testConfigs)));
494 }
495
TEST_F(DefaultVehicleHalTest,testGetAllPropConfigsLarge)496 TEST_F(DefaultVehicleHalTest, testGetAllPropConfigsLarge) {
497 std::vector<VehiclePropConfig> testConfigs;
498 // 5000 VehiclePropConfig exceeds 4k memory limit, so it would be sent through shared memory.
499 for (size_t i = 0; i < 5000; i++) {
500 testConfigs.push_back(VehiclePropConfig{
501 .prop = static_cast<int32_t>(i),
502 });
503 }
504
505 auto hardware = std::make_unique<MockVehicleHardware>();
506 hardware->setPropertyConfigs(testConfigs);
507 auto vhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
508 std::shared_ptr<IVehicle> client = IVehicle::fromBinder(vhal->asBinder());
509
510 VehiclePropConfigs output;
511 auto status = client->getAllPropConfigs(&output);
512
513 ASSERT_TRUE(status.isOk()) << "getAllPropConfigs failed: " << status.getMessage();
514 ASSERT_TRUE(output.payloads.empty());
515 auto result = LargeParcelableBase::stableLargeParcelableToParcelable(output);
516 ASSERT_TRUE(result.ok()) << "failed to parse result shared memory file: "
517 << result.error().message();
518 ASSERT_EQ(result.value().getObject()->payloads, testConfigs);
519 }
520
TEST_F(DefaultVehicleHalTest,testGetPropConfigs)521 TEST_F(DefaultVehicleHalTest, testGetPropConfigs) {
522 auto testConfigs = std::vector<VehiclePropConfig>({
523 VehiclePropConfig{
524 .prop = 1,
525 },
526 VehiclePropConfig{
527 .prop = 2,
528 },
529 });
530
531 auto hardware = std::make_unique<MockVehicleHardware>();
532 hardware->setPropertyConfigs(testConfigs);
533 auto vhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
534 std::shared_ptr<IVehicle> client = IVehicle::fromBinder(vhal->asBinder());
535
536 VehiclePropConfigs output;
537 auto status = client->getPropConfigs(std::vector<int32_t>({1, 2}), &output);
538
539 ASSERT_TRUE(status.isOk()) << "getPropConfigs failed: " << status.getMessage();
540 ASSERT_EQ(output.payloads, testConfigs);
541 }
542
TEST_F(DefaultVehicleHalTest,testGetPropConfigsInvalidArg)543 TEST_F(DefaultVehicleHalTest, testGetPropConfigsInvalidArg) {
544 auto testConfigs = std::vector<VehiclePropConfig>({
545 VehiclePropConfig{
546 .prop = 1,
547 },
548 VehiclePropConfig{
549 .prop = 2,
550 },
551 });
552
553 auto hardware = std::make_unique<MockVehicleHardware>();
554 hardware->setPropertyConfigs(testConfigs);
555 auto vhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
556 std::shared_ptr<IVehicle> client = IVehicle::fromBinder(vhal->asBinder());
557
558 VehiclePropConfigs output;
559 auto status = client->getPropConfigs(std::vector<int32_t>({1, 2, 3}), &output);
560
561 ASSERT_FALSE(status.isOk()) << "getPropConfigs must fail with invalid prop ID";
562 ASSERT_EQ(status.getServiceSpecificError(), toInt(StatusCode::INVALID_ARG));
563 }
564
TEST_F(DefaultVehicleHalTest,testGetValuesSmall)565 TEST_F(DefaultVehicleHalTest, testGetValuesSmall) {
566 GetValueRequests requests;
567 std::vector<GetValueResult> expectedResults;
568 std::vector<GetValueRequest> expectedHardwareRequests;
569
570 ASSERT_TRUE(getValuesTestCases(10, requests, expectedResults, expectedHardwareRequests).ok());
571
572 getHardware()->addGetValueResponses(expectedResults);
573
574 auto status = getClient()->getValues(getCallbackClient(), requests);
575
576 ASSERT_TRUE(status.isOk()) << "getValues failed: " << status.getMessage();
577
578 EXPECT_EQ(getHardware()->nextGetValueRequests(), expectedHardwareRequests)
579 << "requests to hardware mismatch";
580
581 auto maybeGetValueResults = getCallback()->nextGetValueResults();
582 ASSERT_TRUE(maybeGetValueResults.has_value()) << "no results in callback";
583 EXPECT_EQ(maybeGetValueResults.value().payloads, expectedResults) << "results mismatch";
584 EXPECT_EQ(countClients(), static_cast<size_t>(1));
585 }
586
TEST_F(DefaultVehicleHalTest,testGetValuesLarge)587 TEST_F(DefaultVehicleHalTest, testGetValuesLarge) {
588 GetValueRequests requests;
589 std::vector<GetValueResult> expectedResults;
590 std::vector<GetValueRequest> expectedHardwareRequests;
591
592 ASSERT_TRUE(getValuesTestCases(5000, requests, expectedResults, expectedHardwareRequests).ok())
593 << "requests to hardware mismatch";
594
595 getHardware()->addGetValueResponses(expectedResults);
596
597 auto status = getClient()->getValues(getCallbackClient(), requests);
598
599 ASSERT_TRUE(status.isOk()) << "getValues failed: " << status.getMessage();
600
601 EXPECT_EQ(getHardware()->nextGetValueRequests(), expectedHardwareRequests);
602
603 auto maybeGetValueResults = getCallback()->nextGetValueResults();
604 ASSERT_TRUE(maybeGetValueResults.has_value()) << "no results in callback";
605 const GetValueResults& getValueResults = maybeGetValueResults.value();
606 ASSERT_TRUE(getValueResults.payloads.empty())
607 << "payload should be empty, shared memory file should be used";
608
609 auto result = LargeParcelableBase::stableLargeParcelableToParcelable(getValueResults);
610 ASSERT_TRUE(result.ok()) << "failed to parse shared memory file";
611 ASSERT_EQ(result.value().getObject()->payloads, expectedResults) << "results mismatch";
612 EXPECT_EQ(countClients(), static_cast<size_t>(1));
613 }
614
TEST_F(DefaultVehicleHalTest,testGetValuesErrorFromHardware)615 TEST_F(DefaultVehicleHalTest, testGetValuesErrorFromHardware) {
616 GetValueRequests requests;
617 std::vector<GetValueResult> expectedResults;
618 std::vector<GetValueRequest> expectedHardwareRequests;
619
620 ASSERT_TRUE(getValuesTestCases(10, requests, expectedResults, expectedHardwareRequests).ok());
621
622 getHardware()->setStatus("getValues", StatusCode::INTERNAL_ERROR);
623
624 auto status = getClient()->getValues(getCallbackClient(), requests);
625
626 ASSERT_FALSE(status.isOk()) << "expect getValues to fail when hardware returns error";
627 ASSERT_EQ(status.getServiceSpecificError(), toInt(StatusCode::INTERNAL_ERROR));
628 }
629
TEST_F(DefaultVehicleHalTest,testGetValuesInvalidLargeParcelableInput)630 TEST_F(DefaultVehicleHalTest, testGetValuesInvalidLargeParcelableInput) {
631 GetValueRequests requests;
632 requests.sharedMemoryFd = ScopedFileDescriptor(0);
633
634 auto status = getClient()->getValues(getCallbackClient(), requests);
635
636 ASSERT_FALSE(status.isOk()) << "expect getValues to fail when input parcelable is not valid";
637 ASSERT_EQ(status.getServiceSpecificError(), toInt(StatusCode::INVALID_ARG));
638 }
639
TEST_F(DefaultVehicleHalTest,testGetValuesNoReadPermission)640 TEST_F(DefaultVehicleHalTest, testGetValuesNoReadPermission) {
641 GetValueRequests requests = {
642 .sharedMemoryFd = {},
643 .payloads =
644 {
645 {
646 .requestId = 0,
647 .prop =
648 {
649 .prop = WRITE_ONLY_PROP,
650 },
651 },
652 },
653 };
654
655 auto status = getClient()->getValues(getCallbackClient(), requests);
656
657 ASSERT_TRUE(status.isOk()) << "getValue with no read permission should return okay with error "
658 "returned from callback"
659 << ", error: " << status.getMessage();
660 EXPECT_TRUE(getHardware()->nextGetValueRequests().empty()) << "expect no request to hardware";
661
662 auto maybeResult = getCallback()->nextGetValueResults();
663 ASSERT_TRUE(maybeResult.has_value()) << "no results in callback";
664 EXPECT_EQ(maybeResult.value().payloads, std::vector<GetValueResult>({
665 {
666 .requestId = 0,
667 .status = StatusCode::ACCESS_DENIED,
668 },
669 }))
670 << "expect to get ACCESS_DENIED status if no read permission";
671 }
672
TEST_F(DefaultVehicleHalTest,testGetValuesFinishBeforeTimeout)673 TEST_F(DefaultVehicleHalTest, testGetValuesFinishBeforeTimeout) {
674 // timeout: 0.1s
675 int64_t timeout = 100000000;
676 setTimeout(timeout);
677
678 GetValueRequests requests;
679 std::vector<GetValueResult> expectedResults;
680 std::vector<GetValueRequest> expectedHardwareRequests;
681
682 ASSERT_TRUE(getValuesTestCases(10, requests, expectedResults, expectedHardwareRequests).ok());
683
684 // The response would be returned after 0.05s.
685 getHardware()->setSleepTime(timeout / 2);
686 getHardware()->addGetValueResponses(expectedResults);
687
688 auto status = getClient()->getValues(getCallbackClient(), requests);
689
690 ASSERT_TRUE(status.isOk()) << "getValues failed: " << status.getMessage();
691
692 // Wait for the response.
693 std::this_thread::sleep_for(std::chrono::nanoseconds(timeout));
694
695 auto maybeGetValueResults = getCallback()->nextGetValueResults();
696 ASSERT_TRUE(maybeGetValueResults.has_value()) << "no results in callback";
697 EXPECT_EQ(maybeGetValueResults.value().payloads, expectedResults) << "results mismatch";
698 ASSERT_FALSE(getCallback()->nextGetValueResults().has_value()) << "more results than expected";
699 }
700
TEST_F(DefaultVehicleHalTest,testGetValuesFinishAfterTimeout)701 TEST_F(DefaultVehicleHalTest, testGetValuesFinishAfterTimeout) {
702 // timeout: 0.1s
703 int64_t timeout = 100000000;
704 setTimeout(timeout);
705
706 GetValueRequests requests;
707 std::vector<GetValueResult> expectedResults;
708 std::vector<GetValueRequest> expectedHardwareRequests;
709
710 ASSERT_TRUE(getValuesTestCases(10, requests, expectedResults, expectedHardwareRequests).ok());
711
712 // The response would be returned after 0.2s.
713 getHardware()->setSleepTime(timeout * 2);
714 getHardware()->addGetValueResponses(expectedResults);
715
716 auto status = getClient()->getValues(getCallbackClient(), requests);
717
718 ASSERT_TRUE(status.isOk()) << "getValues failed: " << status.getMessage();
719
720 // Wait for the response.
721 std::this_thread::sleep_for(std::chrono::nanoseconds(timeout * 5));
722
723 for (size_t i = 0; i < expectedResults.size(); i++) {
724 expectedResults[i] = {
725 .requestId = expectedResults[i].requestId,
726 .status = StatusCode::TRY_AGAIN,
727 .prop = std::nullopt,
728 };
729 }
730
731 auto maybeGetValueResults = getCallback()->nextGetValueResults();
732 ASSERT_TRUE(maybeGetValueResults.has_value()) << "no results in callback";
733 ASSERT_THAT(maybeGetValueResults.value().payloads, UnorderedElementsAreArray(expectedResults))
734 << "results mismatch, expect TRY_AGAIN error.";
735 ASSERT_FALSE(getCallback()->nextGetValueResults().has_value()) << "more results than expected";
736 }
737
TEST_F(DefaultVehicleHalTest,testGetValuesDuplicateRequestIdsInTwoRequests)738 TEST_F(DefaultVehicleHalTest, testGetValuesDuplicateRequestIdsInTwoRequests) {
739 // timeout: 0.1s
740 int64_t timeout = 100000000;
741 setTimeout(timeout);
742
743 GetValueRequests requests;
744 std::vector<GetValueResult> expectedResults;
745 std::vector<GetValueRequest> expectedHardwareRequests;
746
747 ASSERT_TRUE(getValuesTestCases(1, requests, expectedResults, expectedHardwareRequests).ok());
748
749 getHardware()->setSleepTime(timeout * 2);
750 getHardware()->addGetValueResponses(expectedResults);
751
752 auto status = getClient()->getValues(getCallbackClient(), requests);
753
754 ASSERT_TRUE(status.isOk()) << "getValues failed: " << status.getMessage();
755
756 // Use the same request ID again.
757 status = getClient()->getValues(getCallbackClient(), requests);
758
759 ASSERT_FALSE(status.isOk())
760 << "Use the same request ID before the previous request finishes must fail";
761
762 // Wait for the request to finish.
763 std::this_thread::sleep_for(std::chrono::nanoseconds(timeout * 5));
764 }
765
TEST_F(DefaultVehicleHalTest,testGetValuesDuplicateRequestIdsInOneRequest)766 TEST_F(DefaultVehicleHalTest, testGetValuesDuplicateRequestIdsInOneRequest) {
767 GetValueRequests requests = {.payloads = {
768 {
769 .requestId = 0,
770 .prop =
771 VehiclePropValue{
772 .prop = testInt32VecProp(0),
773 },
774 },
775 {
776 .requestId = 0,
777 .prop =
778 VehiclePropValue{
779 .prop = testInt32VecProp(1),
780 },
781 },
782 }};
783
784 auto status = getClient()->getValues(getCallbackClient(), requests);
785
786 ASSERT_FALSE(status.isOk()) << "duplicate Ids in one request must fail";
787 }
788
TEST_F(DefaultVehicleHalTest,testGetValuesDuplicateRequestProps)789 TEST_F(DefaultVehicleHalTest, testGetValuesDuplicateRequestProps) {
790 GetValueRequests requests = {.payloads = {
791 {
792 .requestId = 0,
793 .prop =
794 VehiclePropValue{
795 .prop = testInt32VecProp(0),
796 },
797 },
798 {
799 .requestId = 1,
800 .prop =
801 VehiclePropValue{
802 .prop = testInt32VecProp(0),
803 },
804 },
805 }};
806
807 auto status = getClient()->getValues(getCallbackClient(), requests);
808
809 ASSERT_FALSE(status.isOk()) << "duplicate request properties in one request must fail";
810 }
811
TEST_F(DefaultVehicleHalTest,testGetValuesNewClientDied)812 TEST_F(DefaultVehicleHalTest, testGetValuesNewClientDied) {
813 GetValueRequests requests;
814 std::vector<GetValueResult> expectedResults;
815 std::vector<GetValueRequest> expectedHardwareRequests;
816
817 ASSERT_TRUE(getValuesTestCases(10, requests, expectedResults, expectedHardwareRequests).ok());
818
819 getHardware()->addGetValueResponses(expectedResults);
820
821 setBinderAlive(false);
822
823 auto status = getClient()->getValues(getCallbackClient(), requests);
824
825 ASSERT_FALSE(status.isOk()) << "getValues must fail if client died";
826 ASSERT_EQ(status.getExceptionCode(), EX_TRANSACTION_FAILED);
827 EXPECT_EQ(countClients(), static_cast<size_t>(0))
828 << "No client should be created if the client binder died";
829 }
830
TEST_F(DefaultVehicleHalTest,testGetValuesExistingClientDied)831 TEST_F(DefaultVehicleHalTest, testGetValuesExistingClientDied) {
832 GetValueRequests requests;
833 std::vector<GetValueResult> expectedResults;
834 std::vector<GetValueRequest> expectedHardwareRequests;
835
836 ASSERT_TRUE(getValuesTestCases(10, requests, expectedResults, expectedHardwareRequests).ok());
837
838 getHardware()->addGetValueResponses(expectedResults);
839
840 // Try a normal getValue request to cache a GetValueClient first.
841 auto status = getClient()->getValues(getCallbackClient(), requests);
842
843 ASSERT_TRUE(status.isOk()) << "getValues failed: " << status.getMessage();
844 EXPECT_EQ(countClients(), static_cast<size_t>(1));
845
846 // The client binder died before onBinderUnlinked clean up the GetValueClient.
847 setBinderAlive(false);
848
849 status = getClient()->getValues(getCallbackClient(), requests);
850
851 ASSERT_FALSE(status.isOk()) << "getValues must fail if client died";
852 ASSERT_EQ(status.getExceptionCode(), EX_TRANSACTION_FAILED);
853 // The client count should still be 1 but onBinderUnlinked will remove this later.
854 EXPECT_EQ(countClients(), static_cast<size_t>(1));
855 }
856
TEST_F(DefaultVehicleHalTest,testSetValuesSmall)857 TEST_F(DefaultVehicleHalTest, testSetValuesSmall) {
858 SetValueRequests requests;
859 std::vector<SetValueResult> expectedResults;
860 std::vector<SetValueRequest> expectedHardwareRequests;
861
862 ASSERT_TRUE(setValuesTestCases(10, requests, expectedResults, expectedHardwareRequests).ok());
863
864 getHardware()->addSetValueResponses(expectedResults);
865
866 auto status = getClient()->setValues(getCallbackClient(), requests);
867
868 ASSERT_TRUE(status.isOk()) << "setValues failed: " << status.getMessage();
869
870 EXPECT_EQ(getHardware()->nextSetValueRequests(), expectedHardwareRequests)
871 << "requests to hardware mismatch";
872
873 auto maybeSetValueResults = getCallback()->nextSetValueResults();
874 ASSERT_TRUE(maybeSetValueResults.has_value()) << "no results in callback";
875 ASSERT_EQ(maybeSetValueResults.value().payloads, expectedResults) << "results mismatch";
876 EXPECT_EQ(countClients(), static_cast<size_t>(1));
877 }
878
TEST_F(DefaultVehicleHalTest,testSetValuesLarge)879 TEST_F(DefaultVehicleHalTest, testSetValuesLarge) {
880 SetValueRequests requests;
881 std::vector<SetValueResult> expectedResults;
882 std::vector<SetValueRequest> expectedHardwareRequests;
883
884 ASSERT_TRUE(setValuesTestCases(5000, requests, expectedResults, expectedHardwareRequests).ok());
885
886 getHardware()->addSetValueResponses(expectedResults);
887
888 auto status = getClient()->setValues(getCallbackClient(), requests);
889
890 ASSERT_TRUE(status.isOk()) << "setValues failed: " << status.getMessage();
891
892 EXPECT_EQ(getHardware()->nextSetValueRequests(), expectedHardwareRequests)
893 << "requests to hardware mismatch";
894
895 auto maybeSetValueResults = getCallback()->nextSetValueResults();
896 ASSERT_TRUE(maybeSetValueResults.has_value()) << "no results in callback";
897 const SetValueResults& setValueResults = maybeSetValueResults.value();
898 ASSERT_TRUE(setValueResults.payloads.empty())
899 << "payload should be empty, shared memory file should be used";
900
901 auto result = LargeParcelableBase::stableLargeParcelableToParcelable(setValueResults);
902 ASSERT_TRUE(result.ok()) << "failed to parse shared memory file";
903 ASSERT_EQ(result.value().getObject()->payloads, expectedResults) << "results mismatch";
904 EXPECT_EQ(countClients(), static_cast<size_t>(1));
905 }
906
907 class SetValuesInvalidRequestTest
908 : public DefaultVehicleHalTest,
909 public testing::WithParamInterface<SetValuesInvalidRequestTestCase> {};
910
911 INSTANTIATE_TEST_SUITE_P(
912 SetValuesInvalidRequestTests, SetValuesInvalidRequestTest,
913 testing::ValuesIn(getSetValuesInvalidRequestTestCases()),
__anon350b19a40202(const testing::TestParamInfo<SetValuesInvalidRequestTest::ParamType>& info) 914 [](const testing::TestParamInfo<SetValuesInvalidRequestTest::ParamType>& info) {
915 return info.param.name;
916 });
917
TEST_P(SetValuesInvalidRequestTest,testSetValuesInvalidRequest)918 TEST_P(SetValuesInvalidRequestTest, testSetValuesInvalidRequest) {
919 SetValuesInvalidRequestTestCase tc = GetParam();
920 std::vector<SetValueResult> expectedHardwareResults{
921 SetValueResult{
922 .requestId = 1,
923 .status = StatusCode::OK,
924 },
925 };
926 getHardware()->addSetValueResponses(expectedHardwareResults);
927
928 SetValueRequests requests;
929 SetValueRequest invalidRequest{
930 .requestId = 0,
931 .value = tc.request,
932 };
933 SetValueRequest normalRequest{.requestId = 1,
934 .value = {
935 .prop = testInt32VecProp(0),
936 .value.int32Values = {0},
937 }};
938 requests.payloads = {invalidRequest, normalRequest};
939 auto status = getClient()->setValues(getCallbackClient(), requests);
940
941 ASSERT_TRUE(status.isOk()) << "setValues failed: " << status.getMessage();
942
943 EXPECT_EQ(getHardware()->nextSetValueRequests(), std::vector<SetValueRequest>({normalRequest}))
944 << "requests to hardware mismatch";
945
946 auto maybeSetValueResults = getCallback()->nextSetValueResults();
947 ASSERT_TRUE(maybeSetValueResults.has_value()) << "no results in callback";
948 EXPECT_EQ(maybeSetValueResults.value().payloads, std::vector<SetValueResult>({
949 {
950 .requestId = 0,
951 .status = tc.expectedStatus,
952 },
953 }))
954 << "invalid argument result mismatch";
955
956 maybeSetValueResults = getCallback()->nextSetValueResults();
957 ASSERT_TRUE(maybeSetValueResults.has_value()) << "no results from hardware in callback";
958 EXPECT_EQ(maybeSetValueResults.value().payloads, expectedHardwareResults)
959 << "results from hardware mismatch";
960 }
961
TEST_F(DefaultVehicleHalTest,testSetValuesFinishBeforeTimeout)962 TEST_F(DefaultVehicleHalTest, testSetValuesFinishBeforeTimeout) {
963 // timeout: 0.1s
964 int64_t timeout = 100000000;
965 setTimeout(timeout);
966
967 SetValueRequests requests;
968 std::vector<SetValueResult> expectedResults;
969 std::vector<SetValueRequest> expectedHardwareRequests;
970
971 ASSERT_TRUE(setValuesTestCases(10, requests, expectedResults, expectedHardwareRequests).ok());
972
973 // The response would be returned after 0.05s.
974 getHardware()->setSleepTime(timeout / 2);
975 getHardware()->addSetValueResponses(expectedResults);
976
977 auto status = getClient()->setValues(getCallbackClient(), requests);
978
979 ASSERT_TRUE(status.isOk()) << "setValues failed: " << status.getMessage();
980
981 // Wait for the response.
982 std::this_thread::sleep_for(std::chrono::nanoseconds(timeout));
983
984 auto maybeSetValueResults = getCallback()->nextSetValueResults();
985 ASSERT_TRUE(maybeSetValueResults.has_value()) << "no results in callback";
986 EXPECT_EQ(maybeSetValueResults.value().payloads, expectedResults) << "results mismatch";
987 ASSERT_FALSE(getCallback()->nextSetValueResults().has_value()) << "more results than expected";
988 }
989
TEST_F(DefaultVehicleHalTest,testSetValuesFinishAfterTimeout)990 TEST_F(DefaultVehicleHalTest, testSetValuesFinishAfterTimeout) {
991 // timeout: 0.1s
992 int64_t timeout = 100000000;
993 setTimeout(timeout);
994
995 SetValueRequests requests;
996 std::vector<SetValueResult> expectedResults;
997 std::vector<SetValueRequest> expectedHardwareRequests;
998
999 ASSERT_TRUE(setValuesTestCases(10, requests, expectedResults, expectedHardwareRequests).ok());
1000
1001 // The response would be returned after 0.2s.
1002 getHardware()->setSleepTime(timeout * 2);
1003 getHardware()->addSetValueResponses(expectedResults);
1004
1005 auto status = getClient()->setValues(getCallbackClient(), requests);
1006
1007 ASSERT_TRUE(status.isOk()) << "setValues failed: " << status.getMessage();
1008
1009 // Wait for the response.
1010 std::this_thread::sleep_for(std::chrono::nanoseconds(timeout * 5));
1011
1012 for (size_t i = 0; i < expectedResults.size(); i++) {
1013 expectedResults[i] = {
1014 .requestId = expectedResults[i].requestId,
1015 .status = StatusCode::TRY_AGAIN,
1016 };
1017 }
1018
1019 auto maybeSetValueResults = getCallback()->nextSetValueResults();
1020 ASSERT_TRUE(maybeSetValueResults.has_value()) << "no results in callback";
1021 ASSERT_THAT(maybeSetValueResults.value().payloads, UnorderedElementsAreArray(expectedResults))
1022 << "results mismatch, expect TRY_AGAIN error.";
1023 ASSERT_FALSE(getCallback()->nextSetValueResults().has_value()) << "more results than expected";
1024 }
1025
TEST_F(DefaultVehicleHalTest,testSetValuesDuplicateRequestIdsInTwoRequests)1026 TEST_F(DefaultVehicleHalTest, testSetValuesDuplicateRequestIdsInTwoRequests) {
1027 // timeout: 0.1s
1028 int64_t timeout = 100000000;
1029 setTimeout(timeout);
1030
1031 SetValueRequests requests;
1032 std::vector<SetValueResult> expectedResults;
1033 std::vector<SetValueRequest> expectedHardwareRequests;
1034
1035 ASSERT_TRUE(setValuesTestCases(1, requests, expectedResults, expectedHardwareRequests).ok());
1036
1037 getHardware()->setSleepTime(timeout * 2);
1038 getHardware()->addSetValueResponses(expectedResults);
1039
1040 auto status = getClient()->setValues(getCallbackClient(), requests);
1041
1042 ASSERT_TRUE(status.isOk()) << "setValues failed: " << status.getMessage();
1043
1044 // Use the same request ID again.
1045 status = getClient()->setValues(getCallbackClient(), requests);
1046
1047 ASSERT_FALSE(status.isOk())
1048 << "Use the same request ID before the previous request finishes must fail";
1049
1050 // Wait for the request to finish.
1051 std::this_thread::sleep_for(std::chrono::nanoseconds(timeout * 5));
1052 }
1053
TEST_F(DefaultVehicleHalTest,testSetValuesDuplicateRequestIdsInOneRequest)1054 TEST_F(DefaultVehicleHalTest, testSetValuesDuplicateRequestIdsInOneRequest) {
1055 SetValueRequests requests = {.payloads = {
1056 {
1057 .requestId = 0,
1058 .value =
1059 VehiclePropValue{
1060 .prop = testInt32VecProp(0),
1061 .value.int32Values = {0},
1062 },
1063 },
1064 {
1065 .requestId = 0,
1066 .value =
1067 VehiclePropValue{
1068 .prop = testInt32VecProp(1),
1069 .value.int32Values = {0},
1070 },
1071 },
1072 }};
1073
1074 auto status = getClient()->setValues(getCallbackClient(), requests);
1075
1076 ASSERT_FALSE(status.isOk()) << "duplicate Ids in one request must fail";
1077 }
1078
TEST_F(DefaultVehicleHalTest,testSetValuesDuplicateRequestProps)1079 TEST_F(DefaultVehicleHalTest, testSetValuesDuplicateRequestProps) {
1080 SetValueRequests requests = {.payloads = {
1081 {
1082 .requestId = 0,
1083 .value =
1084 VehiclePropValue{
1085 .prop = testInt32VecProp(0),
1086 .value.int32Values = {0},
1087 },
1088 },
1089 {
1090 .requestId = 1,
1091 .value =
1092 VehiclePropValue{
1093 .prop = testInt32VecProp(0),
1094 .value.int32Values = {0},
1095 },
1096 },
1097 }};
1098
1099 auto status = getClient()->setValues(getCallbackClient(), requests);
1100
1101 ASSERT_FALSE(status.isOk()) << "duplicate request properties in one request must fail";
1102 }
1103
TEST_F(DefaultVehicleHalTest,testSubscribeUnsubscribe)1104 TEST_F(DefaultVehicleHalTest, testSubscribeUnsubscribe) {
1105 std::vector<SubscribeOptions> options = {
1106 {
1107 .propId = GLOBAL_ON_CHANGE_PROP,
1108 },
1109 };
1110
1111 auto status = getClient()->subscribe(getCallbackClient(), options, 0);
1112
1113 ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
1114
1115 status = getClient()->unsubscribe(getCallbackClient(),
1116 std::vector<int32_t>({GLOBAL_ON_CHANGE_PROP}));
1117
1118 ASSERT_TRUE(status.isOk()) << "unsubscribe failed: " << status.getMessage();
1119 }
1120
TEST_F(DefaultVehicleHalTest,testSubscribeGlobalOnChangeNormal)1121 TEST_F(DefaultVehicleHalTest, testSubscribeGlobalOnChangeNormal) {
1122 std::vector<SubscribeOptions> options = {
1123 {
1124 .propId = GLOBAL_ON_CHANGE_PROP,
1125 },
1126 };
1127
1128 auto status = getClient()->subscribe(getCallbackClient(), options, 0);
1129
1130 ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
1131
1132 VehiclePropValue testValue{
1133 .prop = GLOBAL_ON_CHANGE_PROP,
1134 .value.int32Values = {0},
1135 };
1136 SetValueRequests setValueRequests = {
1137 .payloads =
1138 {
1139 SetValueRequest{
1140 .requestId = 0,
1141 .value = testValue,
1142 },
1143 },
1144 };
1145 std::vector<SetValueResult> setValueResults = {{
1146 .requestId = 0,
1147 .status = StatusCode::OK,
1148 }};
1149
1150 // Set the value to trigger a property change event.
1151 getHardware()->addSetValueResponses(setValueResults);
1152 status = getClient()->setValues(getCallbackClient(), setValueRequests);
1153
1154 ASSERT_TRUE(status.isOk()) << "setValues failed: " << status.getMessage();
1155
1156 auto maybeResults = getCallback()->nextOnPropertyEventResults();
1157 ASSERT_TRUE(maybeResults.has_value()) << "no results in callback";
1158 ASSERT_THAT(maybeResults.value().payloads, UnorderedElementsAre(testValue))
1159 << "results mismatch, expect on change event for the updated value";
1160 ASSERT_FALSE(getCallback()->nextOnPropertyEventResults().has_value())
1161 << "more results than expected";
1162 EXPECT_EQ(countClients(), static_cast<size_t>(2))
1163 << "expect 2 clients, 1 subscribe client and 1 setvalue client";
1164 }
1165
TEST_F(DefaultVehicleHalTest,testSubscribeGlobalOnchangeUnrelatedEventIgnored)1166 TEST_F(DefaultVehicleHalTest, testSubscribeGlobalOnchangeUnrelatedEventIgnored) {
1167 std::vector<SubscribeOptions> options = {
1168 {
1169 .propId = GLOBAL_ON_CHANGE_PROP,
1170 },
1171 };
1172
1173 auto status = getClient()->subscribe(getCallbackClient(), options, 0);
1174
1175 ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
1176
1177 VehiclePropValue testValue{
1178 .prop = GLOBAL_CONTINUOUS_PROP,
1179 .value.int32Values = {0},
1180 };
1181
1182 // Set the value to trigger a property change event. This event should be ignored because we
1183 // have not subscribed to it.
1184 getHardware()->addSetValueResponses({{
1185 .requestId = 0,
1186 .status = StatusCode::OK,
1187 }});
1188 status = getClient()->setValues(getCallbackClient(),
1189 {
1190 .payloads =
1191 {
1192 SetValueRequest{
1193 .requestId = 0,
1194 .value = testValue,
1195 },
1196 },
1197 });
1198
1199 ASSERT_TRUE(status.isOk()) << "setValues failed: " << status.getMessage();
1200
1201 ASSERT_FALSE(getCallback()->nextOnPropertyEventResults().has_value())
1202 << "must receive no property update event if the property is not subscribed";
1203 }
1204
TEST_F(DefaultVehicleHalTest,testSubscribeAreaOnChange)1205 TEST_F(DefaultVehicleHalTest, testSubscribeAreaOnChange) {
1206 int testAreaId = toInt(VehicleAreaWindow::ROW_1_LEFT);
1207 std::vector<SubscribeOptions> options = {
1208 {
1209 .propId = AREA_ON_CHANGE_PROP,
1210 .areaIds = {testAreaId},
1211 },
1212 };
1213
1214 auto status = getClient()->subscribe(getCallbackClient(), options, 0);
1215
1216 ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
1217
1218 VehiclePropValue testValue{
1219 .prop = AREA_ON_CHANGE_PROP,
1220 .areaId = testAreaId,
1221 .value.int32Values = {0},
1222 };
1223
1224 // Set the value to trigger a property change event.
1225 getHardware()->addSetValueResponses({{
1226 .requestId = 0,
1227 .status = StatusCode::OK,
1228 }});
1229 status = getClient()->setValues(getCallbackClient(),
1230 {
1231 .payloads =
1232 {
1233 SetValueRequest{
1234 .requestId = 0,
1235 .value = testValue,
1236 },
1237 },
1238 });
1239
1240 ASSERT_TRUE(status.isOk()) << "setValues failed: " << status.getMessage();
1241
1242 auto maybeResults = getCallback()->nextOnPropertyEventResults();
1243 ASSERT_TRUE(maybeResults.has_value()) << "no results in callback";
1244 ASSERT_THAT(maybeResults.value().payloads, UnorderedElementsAre(testValue))
1245 << "results mismatch, expect on change event for the updated value";
1246 ASSERT_FALSE(getCallback()->nextOnPropertyEventResults().has_value())
1247 << "more results than expected";
1248 }
1249
TEST_F(DefaultVehicleHalTest,testSubscribeAreaOnChangeAllAreas)1250 TEST_F(DefaultVehicleHalTest, testSubscribeAreaOnChangeAllAreas) {
1251 std::vector<SubscribeOptions> options = {
1252 {
1253 .propId = AREA_ON_CHANGE_PROP,
1254 // No areaIds means subscribing to all area IDs.
1255 .areaIds = {},
1256 },
1257 };
1258
1259 auto status = getClient()->subscribe(getCallbackClient(), options, 0);
1260
1261 ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
1262
1263 VehiclePropValue testValue1{
1264 .prop = AREA_ON_CHANGE_PROP,
1265 .areaId = toInt(VehicleAreaWindow::ROW_1_LEFT),
1266 .value.int32Values = {0},
1267 };
1268 VehiclePropValue testValue2{
1269 .prop = AREA_ON_CHANGE_PROP,
1270 .areaId = toInt(VehicleAreaWindow::ROW_1_RIGHT),
1271 .value.int32Values = {0},
1272 };
1273
1274 // Set the values to trigger property change events for two areas.
1275 getHardware()->addSetValueResponses({{
1276 .requestId = 0,
1277 .status = StatusCode::OK,
1278 },
1279 {
1280 .requestId = 1,
1281 .status = StatusCode::OK,
1282 }});
1283 status = getClient()->setValues(getCallbackClient(),
1284 {
1285 .payloads =
1286 {
1287 SetValueRequest{
1288 .requestId = 0,
1289 .value = testValue1,
1290 },
1291 SetValueRequest{
1292 .requestId = 1,
1293 .value = testValue2,
1294 },
1295 },
1296 });
1297
1298 ASSERT_TRUE(status.isOk()) << "setValues failed: " << status.getMessage();
1299
1300 auto maybeResults = getCallback()->nextOnPropertyEventResults();
1301 ASSERT_TRUE(maybeResults.has_value()) << "no results in callback";
1302 ASSERT_THAT(maybeResults.value().payloads, UnorderedElementsAre(testValue1, testValue2))
1303 << "results mismatch, expect two on-change events for all updated areas";
1304 ASSERT_FALSE(getCallback()->nextOnPropertyEventResults().has_value())
1305 << "more results than expected";
1306 }
1307
TEST_F(DefaultVehicleHalTest,testSubscribeGlobalContinuous)1308 TEST_F(DefaultVehicleHalTest, testSubscribeGlobalContinuous) {
1309 VehiclePropValue testValue{
1310 .prop = GLOBAL_CONTINUOUS_PROP,
1311 };
1312
1313 std::vector<SubscribeOptions> options = {
1314 {
1315 .propId = GLOBAL_CONTINUOUS_PROP,
1316 .sampleRate = 20.0,
1317 },
1318 };
1319
1320 auto status = getClient()->subscribe(getCallbackClient(), options, 0);
1321
1322 ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
1323
1324 // Sleep for 1s, which should generate ~20 events.
1325 std::this_thread::sleep_for(std::chrono::seconds(1));
1326
1327 // Should trigger about 20 times, check for at least 15 events to be safe.
1328 for (size_t i = 0; i < 15; i++) {
1329 auto maybeResults = getCallback()->nextOnPropertyEventResults();
1330 ASSERT_TRUE(maybeResults.has_value()) << "no results in callback";
1331 ASSERT_THAT(maybeResults.value().payloads, UnorderedElementsAre(testValue))
1332 << "results mismatch, expect to get the updated value";
1333 }
1334 EXPECT_EQ(countClients(), static_cast<size_t>(1));
1335 }
1336
TEST_F(DefaultVehicleHalTest,testSubscribeGlobalContinuousRateOutOfRange)1337 TEST_F(DefaultVehicleHalTest, testSubscribeGlobalContinuousRateOutOfRange) {
1338 // The maxSampleRate is 100, so the sample rate should be the default max 100.
1339 std::vector<SubscribeOptions> options = {
1340 {
1341 .propId = GLOBAL_CONTINUOUS_PROP,
1342 .sampleRate = 1000.0,
1343 },
1344 };
1345
1346 auto status = getClient()->subscribe(getCallbackClient(), options, 0);
1347
1348 ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
1349
1350 // Sleep for 1s, which should generate ~100 events.
1351 std::this_thread::sleep_for(std::chrono::seconds(1));
1352
1353 size_t eventCount = getCallback()->countOnPropertyEventResults();
1354 ASSERT_GE(eventCount, 50u) << "expect at least 50 events to be generated";
1355 ASSERT_LE(eventCount, 150u) << "expect no more than 150 events to be generated";
1356
1357 EXPECT_EQ(countClients(), static_cast<size_t>(1));
1358 }
1359
TEST_F(DefaultVehicleHalTest,testSubscribeAreaContinuous)1360 TEST_F(DefaultVehicleHalTest, testSubscribeAreaContinuous) {
1361 std::vector<SubscribeOptions> options = {
1362 {
1363 .propId = AREA_CONTINUOUS_PROP,
1364 .sampleRate = 20.0,
1365 .areaIds = {toInt(VehicleAreaWindow::ROW_1_LEFT)},
1366 },
1367 {
1368 .propId = AREA_CONTINUOUS_PROP,
1369 .sampleRate = 10.0,
1370 .areaIds = {toInt(VehicleAreaWindow::ROW_1_RIGHT)},
1371 },
1372 };
1373
1374 auto status = getClient()->subscribe(getCallbackClient(), options, 0);
1375
1376 ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
1377
1378 // Sleep for 1s, which should generate ~20 events.
1379 std::this_thread::sleep_for(std::chrono::seconds(1));
1380
1381 getClient()->unsubscribe(getCallbackClient(), std::vector<int32_t>({AREA_CONTINUOUS_PROP}));
1382
1383 std::vector<VehiclePropValue> events;
1384 while (true) {
1385 auto maybeResults = getCallback()->nextOnPropertyEventResults();
1386 if (!maybeResults.has_value()) {
1387 break;
1388 }
1389 for (const auto& value : maybeResults.value().payloads) {
1390 events.push_back(value);
1391 }
1392 }
1393
1394 size_t leftCount = 0;
1395 size_t rightCount = 0;
1396
1397 for (const auto& event : events) {
1398 ASSERT_EQ(event.prop, AREA_CONTINUOUS_PROP);
1399 if (event.areaId == toInt(VehicleAreaWindow::ROW_1_LEFT)) {
1400 leftCount++;
1401 continue;
1402 }
1403 rightCount++;
1404 }
1405
1406 // Should trigger about 20 times, check for at least 15 events to be safe.
1407 ASSERT_GE(leftCount, static_cast<size_t>(15));
1408 // Should trigger about 10 times, check for at least 5 events to be safe.
1409 ASSERT_GE(rightCount, static_cast<size_t>(5));
1410 }
1411
TEST_F(DefaultVehicleHalTest,testUnsubscribeOnChange)1412 TEST_F(DefaultVehicleHalTest, testUnsubscribeOnChange) {
1413 std::vector<SubscribeOptions> options = {
1414 {
1415 .propId = GLOBAL_ON_CHANGE_PROP,
1416 },
1417 };
1418
1419 auto status = getClient()->subscribe(getCallbackClient(), options, 0);
1420
1421 ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
1422
1423 status = getClient()->unsubscribe(getCallbackClient(),
1424 std::vector<int32_t>({GLOBAL_ON_CHANGE_PROP}));
1425
1426 ASSERT_TRUE(status.isOk()) << "unsubscribe failed: " << status.getMessage();
1427
1428 VehiclePropValue testValue{
1429 .prop = GLOBAL_ON_CHANGE_PROP,
1430 .value.int32Values = {0},
1431 };
1432
1433 // Set the value to trigger a property change event.
1434 getHardware()->addSetValueResponses({{
1435 .requestId = 0,
1436 .status = StatusCode::OK,
1437 }});
1438 status = getClient()->setValues(getCallbackClient(),
1439 {
1440 .payloads =
1441 {
1442 SetValueRequest{
1443 .requestId = 0,
1444 .value = testValue,
1445 },
1446 },
1447 });
1448
1449 ASSERT_TRUE(status.isOk()) << "setValues failed: " << status.getMessage();
1450
1451 ASSERT_FALSE(getCallback()->nextOnPropertyEventResults().has_value())
1452 << "No property event should be generated after unsubscription";
1453 }
1454
TEST_F(DefaultVehicleHalTest,testUnsubscribeContinuous)1455 TEST_F(DefaultVehicleHalTest, testUnsubscribeContinuous) {
1456 std::vector<SubscribeOptions> options = {
1457 {
1458 .propId = GLOBAL_CONTINUOUS_PROP,
1459 .sampleRate = 20.0,
1460 },
1461 };
1462
1463 auto status = getClient()->subscribe(getCallbackClient(), options, 0);
1464
1465 ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
1466
1467 status = getClient()->unsubscribe(getCallbackClient(),
1468 std::vector<int32_t>({GLOBAL_CONTINUOUS_PROP}));
1469
1470 ASSERT_TRUE(status.isOk()) << "unsubscribe failed: " << status.getMessage();
1471
1472 // Clear existing events.
1473 while (getCallback()->nextOnPropertyEventResults().has_value()) {
1474 // Do nothing.
1475 }
1476
1477 // Wait for a while, make sure no new events are generated.
1478 std::this_thread::sleep_for(std::chrono::milliseconds(100));
1479
1480 ASSERT_FALSE(getCallback()->nextOnPropertyEventResults().has_value())
1481 << "No property event should be generated after unsubscription";
1482 }
1483
1484 class SubscribeInvalidOptionsTest
1485 : public DefaultVehicleHalTest,
1486 public testing::WithParamInterface<SubscribeInvalidOptionsTestCase> {};
1487
1488 INSTANTIATE_TEST_SUITE_P(
1489 SubscribeInvalidOptionsTests, SubscribeInvalidOptionsTest,
1490 testing::ValuesIn(getSubscribeInvalidOptionsTestCases()),
__anon350b19a40302(const testing::TestParamInfo<SubscribeInvalidOptionsTest::ParamType>& info) 1491 [](const testing::TestParamInfo<SubscribeInvalidOptionsTest::ParamType>& info) {
1492 return info.param.name;
1493 });
1494
TEST_P(SubscribeInvalidOptionsTest,testSubscribeInvalidOptions)1495 TEST_P(SubscribeInvalidOptionsTest, testSubscribeInvalidOptions) {
1496 std::vector<SubscribeOptions> options = {GetParam().option};
1497
1498 auto status = getClient()->subscribe(getCallbackClient(), options, 0);
1499
1500 ASSERT_FALSE(status.isOk()) << "invalid subscribe options must fail";
1501 ASSERT_EQ(status.getServiceSpecificError(), toInt(StatusCode::INVALID_ARG));
1502 }
1503
TEST_F(DefaultVehicleHalTest,testSubscribeNoReadPermission)1504 TEST_F(DefaultVehicleHalTest, testSubscribeNoReadPermission) {
1505 std::vector<SubscribeOptions> options = {{
1506 .propId = WRITE_ONLY_PROP,
1507 }};
1508
1509 auto status = getClient()->subscribe(getCallbackClient(), options, 0);
1510
1511 ASSERT_FALSE(status.isOk()) << "subscribe to a write-only property must fail";
1512 ASSERT_EQ(status.getServiceSpecificError(), toInt(StatusCode::ACCESS_DENIED));
1513 }
1514
TEST_F(DefaultVehicleHalTest,testUnsubscribeFailure)1515 TEST_F(DefaultVehicleHalTest, testUnsubscribeFailure) {
1516 auto status = getClient()->unsubscribe(getCallbackClient(),
1517 std::vector<int32_t>({GLOBAL_ON_CHANGE_PROP}));
1518
1519 ASSERT_FALSE(status.isOk()) << "unsubscribe to a not-subscribed property must fail";
1520 ASSERT_EQ(status.getServiceSpecificError(), toInt(StatusCode::INVALID_ARG));
1521 }
1522
TEST_F(DefaultVehicleHalTest,testHeartbeatEvent)1523 TEST_F(DefaultVehicleHalTest, testHeartbeatEvent) {
1524 std::vector<SubscribeOptions> options = {{
1525 .propId = toInt(VehicleProperty::VHAL_HEARTBEAT),
1526 }};
1527 int64_t currentTime = uptimeMillis();
1528 auto status = getClient()->subscribe(getCallbackClient(), options, 0);
1529
1530 ASSERT_TRUE(status.isOk()) << "unable to subscribe to heartbeat event: " << status.getMessage();
1531
1532 // We send out a heartbeat event every 3s, so sleep for 3s.
1533 std::this_thread::sleep_for(std::chrono::seconds(3));
1534
1535 auto maybeResults = getCallback()->nextOnPropertyEventResults();
1536 ASSERT_TRUE(maybeResults.has_value()) << "no results in callback";
1537 ASSERT_EQ(maybeResults.value().payloads.size(), static_cast<size_t>(1));
1538 VehiclePropValue gotValue = maybeResults.value().payloads[0];
1539 ASSERT_EQ(gotValue.prop, toInt(VehicleProperty::VHAL_HEARTBEAT));
1540 ASSERT_EQ(gotValue.value.int64Values.size(), static_cast<size_t>(1));
1541 ASSERT_GE(gotValue.value.int64Values[0], currentTime)
1542 << "expect to get the latest timestamp with the heartbeat event";
1543 }
1544
TEST_F(DefaultVehicleHalTest,testOnBinderDiedUnlinked)1545 TEST_F(DefaultVehicleHalTest, testOnBinderDiedUnlinked) {
1546 // Set responses for all the hardware getValues requests.
1547 getHardware()->setGetValueResponder(
1548 [](std::shared_ptr<const IVehicleHardware::GetValuesCallback> callback,
1549 const std::vector<GetValueRequest>& requests) {
1550 std::vector<GetValueResult> results;
1551 for (auto& request : requests) {
1552 VehiclePropValue prop = request.prop;
1553 prop.value.int32Values = {0};
1554 results.push_back({
1555 .requestId = request.requestId,
1556 .status = StatusCode::OK,
1557 .prop = prop,
1558 });
1559 }
1560 (*callback)(results);
1561 return StatusCode::OK;
1562 });
1563 std::vector<SubscribeOptions> options = {
1564 {
1565 .propId = GLOBAL_CONTINUOUS_PROP,
1566 .sampleRate = 20.0,
1567 },
1568 };
1569 auto status = getClient()->subscribe(getCallbackClient(), options, 0);
1570 ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
1571 // Sleep for 100ms so that the subscriptionClient gets created because we would at least try to
1572 // get value once.
1573 std::this_thread::sleep_for(std::chrono::milliseconds(100));
1574
1575 // Issue another getValue request on the same client.
1576 GetValueRequests requests;
1577 std::vector<GetValueResult> expectedResults;
1578 std::vector<GetValueRequest> expectedHardwareRequests;
1579 ASSERT_TRUE(getValuesTestCases(1, requests, expectedResults, expectedHardwareRequests).ok());
1580 getHardware()->addGetValueResponses(expectedResults);
1581 status = getClient()->getValues(getCallbackClient(), requests);
1582 ASSERT_TRUE(status.isOk()) << "getValues failed: " << status.getMessage();
1583
1584 ASSERT_EQ(countOnBinderDiedContexts(), static_cast<size_t>(1))
1585 << "expect one OnBinderDied context when one client is registered";
1586
1587 // Get the death recipient cookie for our callback that would be used in onBinderDied and
1588 // onBinderUnlinked.
1589 AIBinder* clientId = getCallbackClient()->asBinder().get();
1590 void* context = getOnBinderDiedContexts(clientId);
1591
1592 onBinderDied(context);
1593
1594 // Sleep for 100ms between checks.
1595 int64_t sleep = 100;
1596 // Timeout: 10s.
1597 int64_t timeout = 10'000'000'000;
1598 int64_t stopTime = elapsedRealtimeNano() + timeout;
1599 // Wait until the onBinderDied event is handled.
1600 while (countClients() != 0u && elapsedRealtimeNano() <= stopTime) {
1601 std::this_thread::sleep_for(std::chrono::milliseconds(sleep));
1602 }
1603
1604 ASSERT_EQ(countClients(), static_cast<size_t>(0))
1605 << "expect all clients to be removed when binder died";
1606 ASSERT_TRUE(hasNoSubscriptions()) << "expect no subscriptions when binder died";
1607
1608 onBinderUnlinked(context);
1609
1610 stopTime = elapsedRealtimeNano() + timeout;
1611 // Wait until the onBinderUnlinked event is handled.
1612 while (countOnBinderDiedContexts() != 0u && elapsedRealtimeNano() <= stopTime) {
1613 std::this_thread::sleep_for(std::chrono::milliseconds(sleep));
1614 }
1615
1616 ASSERT_EQ(countOnBinderDiedContexts(), static_cast<size_t>(0))
1617 << "expect OnBinderDied context to be deleted when binder is unlinked";
1618 }
1619
TEST_F(DefaultVehicleHalTest,testDumpCallerShouldDump)1620 TEST_F(DefaultVehicleHalTest, testDumpCallerShouldDump) {
1621 std::string buffer = "Dump from hardware";
1622 getHardware()->setDumpResult({
1623 .callerShouldDumpState = true,
1624 .buffer = buffer,
1625 });
1626 int fd = memfd_create("memfile", 0);
1627 getClient()->dump(fd, nullptr, 0);
1628
1629 lseek(fd, 0, SEEK_SET);
1630 char buf[10240] = {};
1631 read(fd, buf, sizeof(buf));
1632 close(fd);
1633
1634 std::string msg(buf);
1635
1636 ASSERT_THAT(msg, ContainsRegex(buffer + "\nVehicle HAL State: \n"));
1637 }
1638
TEST_F(DefaultVehicleHalTest,testDumpCallerShouldNotDump)1639 TEST_F(DefaultVehicleHalTest, testDumpCallerShouldNotDump) {
1640 std::string buffer = "Dump from hardware";
1641 getHardware()->setDumpResult({
1642 .callerShouldDumpState = false,
1643 .buffer = buffer,
1644 });
1645 int fd = memfd_create("memfile", 0);
1646 getClient()->dump(fd, nullptr, 0);
1647
1648 lseek(fd, 0, SEEK_SET);
1649 char buf[10240] = {};
1650 read(fd, buf, sizeof(buf));
1651 close(fd);
1652
1653 std::string msg(buf);
1654
1655 ASSERT_THAT(msg, ContainsRegex(buffer));
1656 ASSERT_EQ(msg.find("Vehicle HAL State: "), std::string::npos);
1657 }
1658
1659 } // namespace vehicle
1660 } // namespace automotive
1661 } // namespace hardware
1662 } // namespace android
1663