• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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