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: 43 MockedVehicleHal() { 44 mConfigs.assign(std::begin(kVehicleProperties), 45 std::end(kVehicleProperties)); 46 } 47 48 std::vector<VehiclePropConfig> listProperties() override { 49 return mConfigs; 50 } 51 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 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 107 StatusCode subscribe(int32_t /* property */, 108 int32_t /* areas */, 109 float /* sampleRate */) override { 110 return StatusCode::OK; 111 } 112 113 StatusCode unsubscribe(int32_t /* property */) override { 114 return StatusCode::OK; 115 } 116 117 void sendPropEvent(recyclable_ptr<VehiclePropValue> value) { 118 doHalEvent(std::move(value)); 119 } 120 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: 130 int64_t makeKey(const VehiclePropValue& v) const { 131 return makeKey(v.prop, v.areaId); 132 } 133 134 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: 145 void SetUp() override { 146 hal.reset(new MockedVehicleHal); 147 manager.reset(new VehicleHalManager(hal.get())); 148 149 objectPool = hal->getValuePool(); 150 } 151 152 void TearDown() override { 153 manager.reset(nullptr); 154 hal.reset(nullptr); 155 } 156 public: 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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