1 /*
2 * Copyright (C) 2016 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 <unordered_map>
18 #include <iostream>
19
20 #include <utils/SystemClock.h>
21
22 #include <gtest/gtest.h>
23
24 #include "vhal_v2_0/VehicleHalManager.h"
25
26 #include "VehicleHalTestUtils.h"
27
28 namespace android {
29 namespace hardware {
30 namespace automotive {
31 namespace vehicle {
32 namespace V2_0 {
33
34 namespace {
35
36 using namespace std::placeholders;
37
38 constexpr char kCarMake[] = "Default Car";
39 constexpr int kRetriablePropMockedAttempts = 3;
40
41 class MockedVehicleHal : public VehicleHal {
42 public:
MockedVehicleHal()43 MockedVehicleHal() {
44 mConfigs.assign(std::begin(kVehicleProperties),
45 std::end(kVehicleProperties));
46 }
47
listProperties()48 std::vector<VehiclePropConfig> listProperties() override {
49 return mConfigs;
50 }
51
get(const VehiclePropValue & requestedPropValue,StatusCode * outStatus)52 VehiclePropValuePtr get(const VehiclePropValue& requestedPropValue,
53 StatusCode* outStatus) override {
54 *outStatus = StatusCode::OK;
55 VehiclePropValuePtr pValue;
56 auto property = static_cast<VehicleProperty>(requestedPropValue.prop);
57 int32_t areaId = requestedPropValue.areaId;
58
59 switch (property) {
60 case VehicleProperty::INFO_MAKE:
61 pValue = getValuePool()->obtainString(kCarMake);
62 break;
63 case VehicleProperty::INFO_FUEL_CAPACITY:
64 if (fuelCapacityAttemptsLeft-- > 0) {
65 // Emulate property not ready yet.
66 *outStatus = StatusCode::TRY_AGAIN;
67 } else {
68 pValue = getValuePool()->obtainFloat(42.42);
69 }
70 break;
71 default:
72 if (requestedPropValue.prop == kCustomComplexProperty) {
73 pValue = getValuePool()->obtainComplex();
74 pValue->value.int32Values = hidl_vec<int32_t> { 10, 20 };
75 pValue->value.int64Values = hidl_vec<int64_t> { 30, 40 };
76 pValue->value.floatValues = hidl_vec<float_t> { 1.1, 2.2 };
77 pValue->value.bytes = hidl_vec<uint8_t> { 1, 2, 3 };
78 pValue->value.stringValue = kCarMake;
79 break;
80 }
81 auto key = makeKey(toInt(property), areaId);
82 if (mValues.count(key) == 0) {
83 ALOGW("");
84 }
85 pValue = getValuePool()->obtain(mValues[key]);
86 }
87
88 if (*outStatus == StatusCode::OK && pValue.get() != nullptr) {
89 pValue->prop = toInt(property);
90 pValue->areaId = areaId;
91 pValue->timestamp = elapsedRealtimeNano();
92 }
93
94 return pValue;
95 }
96
set(const VehiclePropValue & propValue)97 StatusCode set(const VehiclePropValue& propValue) override {
98 if (toInt(VehicleProperty::MIRROR_FOLD) == propValue.prop
99 && mirrorFoldAttemptsLeft-- > 0) {
100 return StatusCode::TRY_AGAIN;
101 }
102
103 mValues[makeKey(propValue)] = propValue;
104 return StatusCode::OK;
105 }
106
subscribe(int32_t,int32_t,float)107 StatusCode subscribe(int32_t /* property */,
108 int32_t /* areas */,
109 float /* sampleRate */) override {
110 return StatusCode::OK;
111 }
112
unsubscribe(int32_t)113 StatusCode unsubscribe(int32_t /* property */) override {
114 return StatusCode::OK;
115 }
116
sendPropEvent(recyclable_ptr<VehiclePropValue> value)117 void sendPropEvent(recyclable_ptr<VehiclePropValue> value) {
118 doHalEvent(std::move(value));
119 }
120
sendHalError(StatusCode error,int32_t property,int32_t areaId)121 void sendHalError(StatusCode error, int32_t property, int32_t areaId) {
122 doHalPropertySetError(error, property, areaId);
123 }
124
125 public:
126 int fuelCapacityAttemptsLeft = kRetriablePropMockedAttempts;
127 int mirrorFoldAttemptsLeft = kRetriablePropMockedAttempts;
128
129 private:
makeKey(const VehiclePropValue & v) const130 int64_t makeKey(const VehiclePropValue& v) const {
131 return makeKey(v.prop, v.areaId);
132 }
133
makeKey(int32_t prop,int32_t area) const134 int64_t makeKey(int32_t prop, int32_t area) const {
135 return (static_cast<int64_t>(prop) << 32) | area;
136 }
137
138 private:
139 std::vector<VehiclePropConfig> mConfigs;
140 std::unordered_map<int64_t, VehiclePropValue> mValues;
141 };
142
143 class VehicleHalManagerTest : public ::testing::Test {
144 protected:
SetUp()145 void SetUp() override {
146 hal.reset(new MockedVehicleHal);
147 manager.reset(new VehicleHalManager(hal.get()));
148
149 objectPool = hal->getValuePool();
150 }
151
TearDown()152 void TearDown() override {
153 manager.reset(nullptr);
154 hal.reset(nullptr);
155 }
156 public:
invokeGet(int32_t property,int32_t areaId)157 void invokeGet(int32_t property, int32_t areaId) {
158 VehiclePropValue requestedValue {};
159 requestedValue.prop = property;
160 requestedValue.areaId = areaId;
161
162 invokeGet(requestedValue);
163 }
164
invokeGet(const VehiclePropValue & requestedPropValue)165 void invokeGet(const VehiclePropValue& requestedPropValue) {
166 actualValue = VehiclePropValue {}; // reset previous values
167
168 StatusCode refStatus;
169 VehiclePropValue refValue;
170 bool called = false;
171 manager->get(requestedPropValue, [&refStatus, &refValue, &called]
172 (StatusCode status, const VehiclePropValue& value) {
173 refStatus = status;
174 refValue = value;
175 called = true;
176 });
177 ASSERT_TRUE(called) << "callback wasn't called for prop: "
178 << hexString(requestedPropValue.prop);
179
180 actualValue = refValue;
181 actualStatusCode = refStatus;
182 }
183
184 public:
185 VehiclePropValue actualValue;
186 StatusCode actualStatusCode;
187
188 VehiclePropValuePool* objectPool;
189 std::unique_ptr<MockedVehicleHal> hal;
190 std::unique_ptr<VehicleHalManager> manager;
191 };
192
TEST_F(VehicleHalManagerTest,getPropConfigs)193 TEST_F(VehicleHalManagerTest, getPropConfigs) {
194 hidl_vec<int32_t> properties =
195 { toInt(VehicleProperty::HVAC_FAN_SPEED),
196 toInt(VehicleProperty::INFO_MAKE) };
197 bool called = false;
198
199 manager->getPropConfigs(properties,
200 [&called] (StatusCode status,
201 const hidl_vec<VehiclePropConfig>& c) {
202 ASSERT_EQ(StatusCode::OK, status);
203 ASSERT_EQ(2u, c.size());
204 called = true;
205 });
206
207 ASSERT_TRUE(called); // Verify callback received.
208
209 called = false;
210 manager->getPropConfigs({ toInt(VehicleProperty::HVAC_FAN_SPEED) },
211 [&called] (StatusCode status,
212 const hidl_vec<VehiclePropConfig>& c) {
213 ASSERT_EQ(StatusCode::OK, status);
214 ASSERT_EQ(1u, c.size());
215 ASSERT_EQ(toString(kVehicleProperties[1]), toString(c[0]));
216 called = true;
217 });
218 ASSERT_TRUE(called); // Verify callback received.
219
220 // TODO(pavelm): add case case when property was not declared.
221 }
222
TEST_F(VehicleHalManagerTest,getAllPropConfigs)223 TEST_F(VehicleHalManagerTest, getAllPropConfigs) {
224 bool called = false;
225 manager->getAllPropConfigs(
226 [&called] (const hidl_vec<VehiclePropConfig>& propConfigs) {
227 ASSERT_EQ(arraysize(kVehicleProperties), propConfigs.size());
228
229 for (size_t i = 0; i < propConfigs.size(); i++) {
230 ASSERT_EQ(toString(kVehicleProperties[i]),
231 toString(propConfigs[i]));
232 }
233 called = true;
234 });
235 ASSERT_TRUE(called); // Verify callback received.
236 }
237
TEST_F(VehicleHalManagerTest,halErrorEvent)238 TEST_F(VehicleHalManagerTest, halErrorEvent) {
239 const auto PROP = toInt(VehicleProperty::DISPLAY_BRIGHTNESS);
240
241 sp<MockedVehicleCallback> cb = new MockedVehicleCallback();
242
243 hidl_vec<SubscribeOptions> options = {
244 SubscribeOptions {
245 .propId = PROP,
246 .flags = SubscribeFlags::DEFAULT
247 },
248 };
249
250 StatusCode res = manager->subscribe(cb, options);
251 ASSERT_EQ(StatusCode::OK, res);
252
253 hal->sendHalError(StatusCode::TRY_AGAIN, PROP, 0 /* area id*/);
254 }
255
TEST_F(VehicleHalManagerTest,subscribe)256 TEST_F(VehicleHalManagerTest, subscribe) {
257 const auto PROP = toInt(VehicleProperty::DISPLAY_BRIGHTNESS);
258
259 sp<MockedVehicleCallback> cb = new MockedVehicleCallback();
260
261 hidl_vec<SubscribeOptions> options = {
262 SubscribeOptions {
263 .propId = PROP,
264 .flags = SubscribeFlags::DEFAULT
265 }
266 };
267
268 StatusCode res = manager->subscribe(cb, options);
269 ASSERT_EQ(StatusCode::OK, res);
270
271 auto unsubscribedValue = objectPool->obtain(VehiclePropertyType::INT32);
272 unsubscribedValue->prop = toInt(VehicleProperty::HVAC_FAN_SPEED);
273
274 hal->sendPropEvent(std::move(unsubscribedValue));
275 auto& receivedEnvents = cb->getReceivedEvents();
276
277 ASSERT_TRUE(cb->waitForExpectedEvents(0)) << " Unexpected events received: "
278 << receivedEnvents.size()
279 << (receivedEnvents.size() > 0
280 ? toString(receivedEnvents.front()[0]) : "");
281
282 auto subscribedValue = objectPool->obtain(VehiclePropertyType::INT32);
283 subscribedValue->prop = PROP;
284 subscribedValue->value.int32Values[0] = 42;
285
286 cb->reset();
287 VehiclePropValue actualValue(*subscribedValue.get());
288 hal->sendPropEvent(std::move(subscribedValue));
289
290 ASSERT_TRUE(cb->waitForExpectedEvents(1)) << "Events received: "
291 << receivedEnvents.size();
292
293 ASSERT_EQ(toString(actualValue),
294 toString(cb->getReceivedEvents().front()[0]));
295 }
296
TEST_F(VehicleHalManagerTest,subscribe_WriteOnly)297 TEST_F(VehicleHalManagerTest, subscribe_WriteOnly) {
298 const auto PROP = toInt(VehicleProperty::HVAC_SEAT_TEMPERATURE);
299
300 sp<MockedVehicleCallback> cb = new MockedVehicleCallback();
301
302 hidl_vec<SubscribeOptions> options = {
303 SubscribeOptions {
304 .propId = PROP,
305 .flags = SubscribeFlags::HAL_EVENT
306 },
307 };
308
309 StatusCode res = manager->subscribe(cb, options);
310 // Unable to subscribe on Hal Events for write-only properties.
311 ASSERT_EQ(StatusCode::INVALID_ARG, res);
312
313
314 options[0].flags = SubscribeFlags::SET_CALL;
315
316 res = manager->subscribe(cb, options);
317 // OK to subscribe on SET method call for write-only properties.
318 ASSERT_EQ(StatusCode::OK, res);
319 }
320
TEST_F(VehicleHalManagerTest,get_Complex)321 TEST_F(VehicleHalManagerTest, get_Complex) {
322 invokeGet(kCustomComplexProperty, 0);
323
324 ASSERT_EQ(StatusCode::OK, actualStatusCode);
325 ASSERT_EQ(kCustomComplexProperty, actualValue.prop);
326
327 ASSERT_EQ(3u, actualValue.value.bytes.size());
328 ASSERT_EQ(1, actualValue.value.bytes[0]);
329 ASSERT_EQ(2, actualValue.value.bytes[1]);
330 ASSERT_EQ(3, actualValue.value.bytes[2]);
331
332 ASSERT_EQ(2u, actualValue.value.int32Values.size());
333 ASSERT_EQ(10, actualValue.value.int32Values[0]);
334 ASSERT_EQ(20, actualValue.value.int32Values[1]);
335
336 ASSERT_EQ(2u, actualValue.value.floatValues.size());
337 ASSERT_FLOAT_EQ(1.1, actualValue.value.floatValues[0]);
338 ASSERT_FLOAT_EQ(2.2, actualValue.value.floatValues[1]);
339
340 ASSERT_EQ(2u, actualValue.value.int64Values.size());
341 ASSERT_FLOAT_EQ(30, actualValue.value.int64Values[0]);
342 ASSERT_FLOAT_EQ(40, actualValue.value.int64Values[1]);
343
344 ASSERT_STREQ(kCarMake, actualValue.value.stringValue.c_str());
345 }
346
TEST_F(VehicleHalManagerTest,get_StaticString)347 TEST_F(VehicleHalManagerTest, get_StaticString) {
348 invokeGet(toInt(VehicleProperty::INFO_MAKE), 0);
349
350 ASSERT_EQ(StatusCode::OK, actualStatusCode);
351 ASSERT_EQ(toInt(VehicleProperty::INFO_MAKE), actualValue.prop);
352 ASSERT_STREQ(kCarMake, actualValue.value.stringValue.c_str());
353 }
354
TEST_F(VehicleHalManagerTest,get_NegativeCases)355 TEST_F(VehicleHalManagerTest, get_NegativeCases) {
356 // Write-only property must fail.
357 invokeGet(toInt(VehicleProperty::HVAC_SEAT_TEMPERATURE), 0);
358 ASSERT_EQ(StatusCode::ACCESS_DENIED, actualStatusCode);
359
360 // Unknown property must fail.
361 invokeGet(toInt(VehicleProperty::MIRROR_Z_MOVE), 0);
362 ASSERT_EQ(StatusCode::INVALID_ARG, actualStatusCode);
363 }
364
TEST_F(VehicleHalManagerTest,get_Retriable)365 TEST_F(VehicleHalManagerTest, get_Retriable) {
366 actualStatusCode = StatusCode::TRY_AGAIN;
367 int attempts = 0;
368 while (StatusCode::TRY_AGAIN == actualStatusCode && ++attempts < 10) {
369 invokeGet(toInt(VehicleProperty::INFO_FUEL_CAPACITY), 0);
370
371 }
372 ASSERT_EQ(StatusCode::OK, actualStatusCode);
373 ASSERT_EQ(kRetriablePropMockedAttempts + 1, attempts);
374 ASSERT_FLOAT_EQ(42.42, actualValue.value.floatValues[0]);
375 }
376
TEST_F(VehicleHalManagerTest,set_Basic)377 TEST_F(VehicleHalManagerTest, set_Basic) {
378 const auto PROP = toInt(VehicleProperty::DISPLAY_BRIGHTNESS);
379 const auto VAL = 7;
380
381 auto expectedValue = hal->getValuePool()->obtainInt32(VAL);
382 expectedValue->prop = PROP;
383 expectedValue->areaId = 0;
384
385 actualStatusCode = manager->set(*expectedValue.get());
386 ASSERT_EQ(StatusCode::OK, actualStatusCode);
387
388 invokeGet(PROP, 0);
389 ASSERT_EQ(StatusCode::OK, actualStatusCode);
390 ASSERT_EQ(PROP, actualValue.prop);
391 ASSERT_EQ(VAL, actualValue.value.int32Values[0]);
392 }
393
TEST_F(VehicleHalManagerTest,set_DifferentAreas)394 TEST_F(VehicleHalManagerTest, set_DifferentAreas) {
395 const auto PROP = toInt(VehicleProperty::HVAC_FAN_SPEED);
396 const auto VAL1 = 1;
397 const auto VAL2 = 2;
398 const auto AREA1 = toInt(VehicleAreaZone::ROW_1_LEFT);
399 const auto AREA2 = toInt(VehicleAreaZone::ROW_1_RIGHT);
400
401 {
402 auto expectedValue1 = hal->getValuePool()->obtainInt32(VAL1);
403 expectedValue1->prop = PROP;
404 expectedValue1->areaId = AREA1;
405 actualStatusCode = manager->set(*expectedValue1.get());
406 ASSERT_EQ(StatusCode::OK, actualStatusCode);
407
408 auto expectedValue2 = hal->getValuePool()->obtainInt32(VAL2);
409 expectedValue2->prop = PROP;
410 expectedValue2->areaId = AREA2;
411 actualStatusCode = manager->set(*expectedValue2.get());
412 ASSERT_EQ(StatusCode::OK, actualStatusCode);
413 }
414
415 {
416 invokeGet(PROP, AREA1);
417 ASSERT_EQ(StatusCode::OK, actualStatusCode);
418 ASSERT_EQ(PROP, actualValue.prop);
419 ASSERT_EQ(AREA1, actualValue.areaId);
420 ASSERT_EQ(VAL1, actualValue.value.int32Values[0]);
421
422 invokeGet(PROP, AREA2);
423 ASSERT_EQ(StatusCode::OK, actualStatusCode);
424 ASSERT_EQ(PROP, actualValue.prop);
425 ASSERT_EQ(AREA2, actualValue.areaId);
426 ASSERT_EQ(VAL2, actualValue.value.int32Values[0]);
427 }
428 }
429
TEST_F(VehicleHalManagerTest,set_Retriable)430 TEST_F(VehicleHalManagerTest, set_Retriable) {
431 const auto PROP = toInt(VehicleProperty::MIRROR_FOLD);
432
433 auto v = hal->getValuePool()->obtainBoolean(true);
434 v->prop = PROP;
435 v->areaId = 0;
436
437 actualStatusCode = StatusCode::TRY_AGAIN;
438 int attempts = 0;
439 while (StatusCode::TRY_AGAIN == actualStatusCode && ++attempts < 10) {
440 actualStatusCode = manager->set(*v.get());
441 }
442
443 ASSERT_EQ(StatusCode::OK, actualStatusCode);
444 ASSERT_EQ(kRetriablePropMockedAttempts + 1, attempts);
445
446 invokeGet(PROP, 0);
447 ASSERT_EQ(StatusCode::OK, actualStatusCode);
448 ASSERT_TRUE(actualValue.value.int32Values[0]);
449 }
450
TEST(HalClientVectorTest,basic)451 TEST(HalClientVectorTest, basic) {
452 HalClientVector clients;
453 sp<IVehicleCallback> callback1 = new MockedVehicleCallback();
454
455 sp<HalClient> c1 = new HalClient(callback1);
456 sp<HalClient> c2 = new HalClient(callback1);
457
458 clients.addOrUpdate(c1);
459 clients.addOrUpdate(c1);
460 clients.addOrUpdate(c2);
461 ASSERT_EQ(2u, clients.size());
462 ASSERT_FALSE(clients.isEmpty());
463 ASSERT_LE(0, clients.indexOf(c1));
464 ASSERT_LE(0, clients.remove(c1));
465 ASSERT_GT(0, clients.indexOf(c1)); // c1 was already removed
466 ASSERT_GT(0, clients.remove(c1)); // attempt to remove c1 again
467 ASSERT_LE(0, clients.remove(c2));
468
469 ASSERT_TRUE(clients.isEmpty());
470 }
471
472 } // namespace anonymous
473
474 } // namespace V2_0
475 } // namespace vehicle
476 } // namespace automotive
477 } // namespace hardware
478 } // namespace android
479