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 <android-base/macros.h> 21#include <utils/SystemClock.h> 22 23#include <gtest/gtest.h> 24 25#include "vhal_v2_0/VehicleHalManager.h" 26 27#include "VehicleHalTestUtils.h" 28 29namespace android { 30namespace hardware { 31namespace automotive { 32namespace vehicle { 33namespace V2_0 { 34 35namespace { 36 37using namespace std::placeholders; 38 39constexpr char kCarMake[] = "Default Car"; 40constexpr int kRetriablePropMockedAttempts = 3; 41 42class MockedVehicleHal : public VehicleHal { 43public: 44 MockedVehicleHal() { 45 mConfigs.assign(std::begin(kVehicleProperties), 46 std::end(kVehicleProperties)); 47 } 48 49 std::vector<VehiclePropConfig> listProperties() override { 50 return mConfigs; 51 } 52 53 VehiclePropValuePtr get(const VehiclePropValue& requestedPropValue, 54 StatusCode* outStatus) override { 55 *outStatus = StatusCode::OK; 56 VehiclePropValuePtr pValue; 57 auto property = static_cast<VehicleProperty>(requestedPropValue.prop); 58 int32_t areaId = requestedPropValue.areaId; 59 60 switch (property) { 61 case VehicleProperty::INFO_MAKE: 62 pValue = getValuePool()->obtainString(kCarMake); 63 break; 64 case VehicleProperty::INFO_FUEL_CAPACITY: 65 if (fuelCapacityAttemptsLeft-- > 0) { 66 // Emulate property not ready yet. 67 *outStatus = StatusCode::TRY_AGAIN; 68 } else { 69 pValue = getValuePool()->obtainFloat(42.42); 70 } 71 break; 72 default: 73 if (requestedPropValue.prop == kCustomComplexProperty) { 74 pValue = getValuePool()->obtainComplex(); 75 pValue->value.int32Values = hidl_vec<int32_t> { 10, 20 }; 76 pValue->value.int64Values = hidl_vec<int64_t> { 30, 40 }; 77 pValue->value.floatValues = hidl_vec<float_t> { 1.1, 2.2 }; 78 pValue->value.bytes = hidl_vec<uint8_t> { 1, 2, 3 }; 79 pValue->value.stringValue = kCarMake; 80 break; 81 } 82 auto key = makeKey(toInt(property), areaId); 83 if (mValues.count(key) == 0) { 84 ALOGW(""); 85 } 86 pValue = getValuePool()->obtain(mValues[key]); 87 } 88 89 if (*outStatus == StatusCode::OK && pValue.get() != nullptr) { 90 pValue->prop = toInt(property); 91 pValue->areaId = areaId; 92 pValue->timestamp = elapsedRealtimeNano(); 93 } 94 95 return pValue; 96 } 97 98 StatusCode set(const VehiclePropValue& propValue) override { 99 if (toInt(VehicleProperty::MIRROR_FOLD) == propValue.prop 100 && mirrorFoldAttemptsLeft-- > 0) { 101 return StatusCode::TRY_AGAIN; 102 } 103 104 mValues[makeKey(propValue)] = propValue; 105 return StatusCode::OK; 106 } 107 108 StatusCode subscribe(int32_t /* property */, 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 125public: 126 int fuelCapacityAttemptsLeft = kRetriablePropMockedAttempts; 127 int mirrorFoldAttemptsLeft = kRetriablePropMockedAttempts; 128 129private: 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 138private: 139 std::vector<VehiclePropConfig> mConfigs; 140 std::unordered_map<int64_t, VehiclePropValue> mValues; 141}; 142 143class VehicleHalManagerTest : public ::testing::Test { 144protected: 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 } 156public: 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 184public: 185 VehiclePropValue actualValue; 186 StatusCode actualStatusCode; 187 188 VehiclePropValuePool* objectPool; 189 std::unique_ptr<MockedVehicleHal> hal; 190 std::unique_ptr<VehicleHalManager> manager; 191}; 192 193TEST_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 223TEST_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 238TEST_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{.propId = PROP, .flags = SubscribeFlags::EVENTS_FROM_CAR}, 245 }; 246 247 StatusCode res = manager->subscribe(cb, options); 248 ASSERT_EQ(StatusCode::OK, res); 249 250 hal->sendHalError(StatusCode::TRY_AGAIN, PROP, 0 /* area id*/); 251} 252 253TEST_F(VehicleHalManagerTest, subscribe) { 254 const auto PROP = toInt(VehicleProperty::DISPLAY_BRIGHTNESS); 255 256 sp<MockedVehicleCallback> cb = new MockedVehicleCallback(); 257 258 hidl_vec<SubscribeOptions> options = { 259 SubscribeOptions{.propId = PROP, .flags = SubscribeFlags::EVENTS_FROM_CAR}}; 260 261 StatusCode res = manager->subscribe(cb, options); 262 ASSERT_EQ(StatusCode::OK, res); 263 264 auto unsubscribedValue = objectPool->obtain(VehiclePropertyType::INT32); 265 unsubscribedValue->prop = toInt(VehicleProperty::HVAC_FAN_SPEED); 266 267 hal->sendPropEvent(std::move(unsubscribedValue)); 268 auto& receivedEnvents = cb->getReceivedEvents(); 269 270 ASSERT_TRUE(cb->waitForExpectedEvents(0)) << " Unexpected events received: " 271 << receivedEnvents.size() 272 << (receivedEnvents.size() > 0 273 ? toString(receivedEnvents.front()[0]) : ""); 274 275 auto subscribedValue = objectPool->obtain(VehiclePropertyType::INT32); 276 subscribedValue->prop = PROP; 277 subscribedValue->value.int32Values[0] = 42; 278 279 cb->reset(); 280 VehiclePropValue actualValue(*subscribedValue.get()); 281 actualValue.status = VehiclePropertyStatus::AVAILABLE; 282 hal->sendPropEvent(std::move(subscribedValue)); 283 284 ASSERT_TRUE(cb->waitForExpectedEvents(1)) << "Events received: " 285 << receivedEnvents.size(); 286 287 ASSERT_EQ(toString(actualValue), 288 toString(cb->getReceivedEvents().front()[0])); 289} 290 291TEST_F(VehicleHalManagerTest, subscribe_WriteOnly) { 292 const auto PROP = toInt(VehicleProperty::HVAC_SEAT_TEMPERATURE); 293 294 sp<MockedVehicleCallback> cb = new MockedVehicleCallback(); 295 296 hidl_vec<SubscribeOptions> options = { 297 SubscribeOptions{.propId = PROP, .flags = SubscribeFlags::EVENTS_FROM_CAR}, 298 }; 299 300 StatusCode res = manager->subscribe(cb, options); 301 // Unable to subscribe on Hal Events for write-only properties. 302 ASSERT_EQ(StatusCode::INVALID_ARG, res); 303 304 options[0].flags = SubscribeFlags::EVENTS_FROM_ANDROID; 305 306 res = manager->subscribe(cb, options); 307 // OK to subscribe on SET method call for write-only properties. 308 ASSERT_EQ(StatusCode::OK, res); 309} 310 311TEST_F(VehicleHalManagerTest, get_Complex) { 312 invokeGet(kCustomComplexProperty, 0); 313 314 ASSERT_EQ(StatusCode::OK, actualStatusCode); 315 ASSERT_EQ(kCustomComplexProperty, actualValue.prop); 316 317 ASSERT_EQ(3u, actualValue.value.bytes.size()); 318 ASSERT_EQ(1, actualValue.value.bytes[0]); 319 ASSERT_EQ(2, actualValue.value.bytes[1]); 320 ASSERT_EQ(3, actualValue.value.bytes[2]); 321 322 ASSERT_EQ(2u, actualValue.value.int32Values.size()); 323 ASSERT_EQ(10, actualValue.value.int32Values[0]); 324 ASSERT_EQ(20, actualValue.value.int32Values[1]); 325 326 ASSERT_EQ(2u, actualValue.value.floatValues.size()); 327 ASSERT_FLOAT_EQ(1.1, actualValue.value.floatValues[0]); 328 ASSERT_FLOAT_EQ(2.2, actualValue.value.floatValues[1]); 329 330 ASSERT_EQ(2u, actualValue.value.int64Values.size()); 331 ASSERT_FLOAT_EQ(30, actualValue.value.int64Values[0]); 332 ASSERT_FLOAT_EQ(40, actualValue.value.int64Values[1]); 333 334 ASSERT_STREQ(kCarMake, actualValue.value.stringValue.c_str()); 335} 336 337TEST_F(VehicleHalManagerTest, get_StaticString) { 338 invokeGet(toInt(VehicleProperty::INFO_MAKE), 0); 339 340 ASSERT_EQ(StatusCode::OK, actualStatusCode); 341 ASSERT_EQ(toInt(VehicleProperty::INFO_MAKE), actualValue.prop); 342 ASSERT_STREQ(kCarMake, actualValue.value.stringValue.c_str()); 343} 344 345TEST_F(VehicleHalManagerTest, get_NegativeCases) { 346 // Write-only property must fail. 347 invokeGet(toInt(VehicleProperty::HVAC_SEAT_TEMPERATURE), 0); 348 ASSERT_EQ(StatusCode::ACCESS_DENIED, actualStatusCode); 349 350 // Unknown property must fail. 351 invokeGet(toInt(VehicleProperty::MIRROR_Z_MOVE), 0); 352 ASSERT_EQ(StatusCode::INVALID_ARG, actualStatusCode); 353} 354 355TEST_F(VehicleHalManagerTest, get_Retriable) { 356 actualStatusCode = StatusCode::TRY_AGAIN; 357 int attempts = 0; 358 while (StatusCode::TRY_AGAIN == actualStatusCode && ++attempts < 10) { 359 invokeGet(toInt(VehicleProperty::INFO_FUEL_CAPACITY), 0); 360 361 } 362 ASSERT_EQ(StatusCode::OK, actualStatusCode); 363 ASSERT_EQ(kRetriablePropMockedAttempts + 1, attempts); 364 ASSERT_FLOAT_EQ(42.42, actualValue.value.floatValues[0]); 365} 366 367TEST_F(VehicleHalManagerTest, set_Basic) { 368 const auto PROP = toInt(VehicleProperty::DISPLAY_BRIGHTNESS); 369 const auto VAL = 7; 370 371 auto expectedValue = hal->getValuePool()->obtainInt32(VAL); 372 expectedValue->prop = PROP; 373 expectedValue->areaId = 0; 374 375 actualStatusCode = manager->set(*expectedValue.get()); 376 ASSERT_EQ(StatusCode::OK, actualStatusCode); 377 378 invokeGet(PROP, 0); 379 ASSERT_EQ(StatusCode::OK, actualStatusCode); 380 ASSERT_EQ(PROP, actualValue.prop); 381 ASSERT_EQ(VAL, actualValue.value.int32Values[0]); 382} 383 384TEST_F(VehicleHalManagerTest, set_DifferentAreas) { 385 const auto PROP = toInt(VehicleProperty::HVAC_FAN_SPEED); 386 const auto VAL1 = 1; 387 const auto VAL2 = 2; 388 const auto AREA1 = toInt(VehicleAreaSeat::ROW_1_LEFT); 389 const auto AREA2 = toInt(VehicleAreaSeat::ROW_1_RIGHT); 390 391 { 392 auto expectedValue1 = hal->getValuePool()->obtainInt32(VAL1); 393 expectedValue1->prop = PROP; 394 expectedValue1->areaId = AREA1; 395 actualStatusCode = manager->set(*expectedValue1.get()); 396 ASSERT_EQ(StatusCode::OK, actualStatusCode); 397 398 auto expectedValue2 = hal->getValuePool()->obtainInt32(VAL2); 399 expectedValue2->prop = PROP; 400 expectedValue2->areaId = AREA2; 401 actualStatusCode = manager->set(*expectedValue2.get()); 402 ASSERT_EQ(StatusCode::OK, actualStatusCode); 403 } 404 405 { 406 invokeGet(PROP, AREA1); 407 ASSERT_EQ(StatusCode::OK, actualStatusCode); 408 ASSERT_EQ(PROP, actualValue.prop); 409 ASSERT_EQ(AREA1, actualValue.areaId); 410 ASSERT_EQ(VAL1, actualValue.value.int32Values[0]); 411 412 invokeGet(PROP, AREA2); 413 ASSERT_EQ(StatusCode::OK, actualStatusCode); 414 ASSERT_EQ(PROP, actualValue.prop); 415 ASSERT_EQ(AREA2, actualValue.areaId); 416 ASSERT_EQ(VAL2, actualValue.value.int32Values[0]); 417 } 418} 419 420TEST_F(VehicleHalManagerTest, set_Retriable) { 421 const auto PROP = toInt(VehicleProperty::MIRROR_FOLD); 422 423 auto v = hal->getValuePool()->obtainBoolean(true); 424 v->prop = PROP; 425 v->areaId = 0; 426 427 actualStatusCode = StatusCode::TRY_AGAIN; 428 int attempts = 0; 429 while (StatusCode::TRY_AGAIN == actualStatusCode && ++attempts < 10) { 430 actualStatusCode = manager->set(*v.get()); 431 } 432 433 ASSERT_EQ(StatusCode::OK, actualStatusCode); 434 ASSERT_EQ(kRetriablePropMockedAttempts + 1, attempts); 435 436 invokeGet(PROP, 0); 437 ASSERT_EQ(StatusCode::OK, actualStatusCode); 438 ASSERT_TRUE(actualValue.value.int32Values[0]); 439} 440 441TEST(HalClientVectorTest, basic) { 442 HalClientVector clients; 443 sp<IVehicleCallback> callback1 = new MockedVehicleCallback(); 444 445 sp<HalClient> c1 = new HalClient(callback1); 446 sp<HalClient> c2 = new HalClient(callback1); 447 448 clients.addOrUpdate(c1); 449 clients.addOrUpdate(c1); 450 clients.addOrUpdate(c2); 451 ASSERT_EQ(2u, clients.size()); 452 ASSERT_FALSE(clients.isEmpty()); 453 ASSERT_LE(0, clients.indexOf(c1)); 454 ASSERT_LE(0, clients.remove(c1)); 455 ASSERT_GT(0, clients.indexOf(c1)); // c1 was already removed 456 ASSERT_GT(0, clients.remove(c1)); // attempt to remove c1 again 457 ASSERT_LE(0, clients.remove(c2)); 458 459 ASSERT_TRUE(clients.isEmpty()); 460} 461 462} // namespace anonymous 463 464} // namespace V2_0 465} // namespace vehicle 466} // namespace automotive 467} // namespace hardware 468} // namespace android 469