1 /*
2 * Copyright (C) 2022 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 #define LOG_TAG "VtsHalAutomotiveVehicle"
18
19 #include <AccessForVehicleProperty.h>
20 #include <AnnotationsForVehicleProperty.h>
21 #include <ChangeModeForVehicleProperty.h>
22 #include <EnumForVehicleProperty.h>
23 #include <IVhalClient.h>
24 #include <VehicleHalTypes.h>
25 #include <VehicleUtils.h>
26 #include <VersionForVehicleProperty.h>
27 #include <aidl/Gtest.h>
28 #include <aidl/Vintf.h>
29 #include <aidl/android/hardware/automotive/vehicle/HasSupportedValueInfo.h>
30 #include <aidl/android/hardware/automotive/vehicle/IVehicle.h>
31 #include <android-base/stringprintf.h>
32 #include <android-base/thread_annotations.h>
33 #include <android/binder_process.h>
34 #include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
35 #include <gmock/gmock.h>
36 #include <gtest/gtest.h>
37 #include <hidl/GtestPrinter.h>
38 #include <hidl/ServiceManagement.h>
39 #include <inttypes.h>
40 #include <utils/Log.h>
41 #include <utils/SystemClock.h>
42
43 #include <chrono>
44 #include <mutex>
45 #include <thread>
46 #include <unordered_map>
47 #include <unordered_set>
48 #include <vector>
49
50 using ::aidl::android::hardware::automotive::vehicle::AllowedAccessForVehicleProperty;
51 using ::aidl::android::hardware::automotive::vehicle::AnnotationsForVehicleProperty;
52 using ::aidl::android::hardware::automotive::vehicle::ChangeModeForVehicleProperty;
53 using ::aidl::android::hardware::automotive::vehicle::getSupportedEnumValuesForProperty;
54 using ::aidl::android::hardware::automotive::vehicle::HasSupportedValueInfo;
55 using ::aidl::android::hardware::automotive::vehicle::IVehicle;
56 using ::aidl::android::hardware::automotive::vehicle::MinMaxSupportedValueResult;
57 using ::aidl::android::hardware::automotive::vehicle::PropIdAreaId;
58 using ::aidl::android::hardware::automotive::vehicle::RawPropValues;
59 using ::aidl::android::hardware::automotive::vehicle::StatusCode;
60 using ::aidl::android::hardware::automotive::vehicle::SubscribeOptions;
61 using ::aidl::android::hardware::automotive::vehicle::SupportedValuesListResult;
62 using ::aidl::android::hardware::automotive::vehicle::toString;
63 using ::aidl::android::hardware::automotive::vehicle::VehicleArea;
64 using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
65 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyAccess;
66 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyChangeMode;
67 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyGroup;
68 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyStatus;
69 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyType;
70 using ::aidl::android::hardware::automotive::vehicle::VersionForVehicleProperty;
71 using ::android::getAidlHalInstanceNames;
72 using ::android::uptimeMillis;
73 using ::android::base::ScopedLockAssertion;
74 using ::android::base::StringPrintf;
75 using ::android::frameworks::automotive::vhal::ErrorCode;
76 using ::android::frameworks::automotive::vhal::HalPropError;
77 using ::android::frameworks::automotive::vhal::IHalAreaConfig;
78 using ::android::frameworks::automotive::vhal::IHalPropConfig;
79 using ::android::frameworks::automotive::vhal::IHalPropValue;
80 using ::android::frameworks::automotive::vhal::ISubscriptionCallback;
81 using ::android::frameworks::automotive::vhal::IVhalClient;
82 using ::android::frameworks::automotive::vhal::SubscribeOptionsBuilder;
83 using ::android::frameworks::automotive::vhal::VhalClientResult;
84 using ::android::hardware::getAllHalInstanceNames;
85 using ::android::hardware::Sanitize;
86 using ::android::hardware::automotive::vehicle::isSystemProp;
87 using ::android::hardware::automotive::vehicle::propIdToString;
88 using ::android::hardware::automotive::vehicle::toInt;
89 using ::testing::Ge;
90
91 constexpr int32_t kInvalidProp = 0x31600207;
92 // The timeout for retrying getting prop value after setting prop value.
93 constexpr int64_t kRetryGetPropAfterSetPropTimeoutMillis = 10'000;
94 static constexpr char ANNOTATION_REQUIRE_MIN_MAX_VALUE[] = "require_min_max_supported_value";
95 static constexpr char ANNOTATION_REQUIRE_SUPPORTED_VALUES[] = "require_supported_values_list";
96 static constexpr char ANNOTATION_SUPPORTED_VALUES_IN_CONFIG[] = "legacy_supported_values_in_config";
97 static constexpr char ANNOTATIONS_DATA_ENUM[] = "data_enum";
98
getPropertyType(int32_t propId)99 inline VehiclePropertyType getPropertyType(int32_t propId) {
100 return static_cast<VehiclePropertyType>(propId & toInt(VehiclePropertyType::MASK));
101 }
102
103 struct ServiceDescriptor {
104 std::string name;
105 bool isAidlService;
106 };
107
108 struct PropertyConfigTestParam {
109 VehicleProperty propId;
110 std::vector<VehiclePropertyAccess> accessModes;
111 VehiclePropertyChangeMode changeMode;
112 };
113
114 class VtsVehicleCallback final : public ISubscriptionCallback {
115 private:
116 std::mutex mLock;
117 std::unordered_map<int32_t, std::vector<std::unique_ptr<IHalPropValue>>> mEvents
118 GUARDED_BY(mLock);
119 std::condition_variable mEventCond;
120
121 public:
onPropertyEvent(const std::vector<std::unique_ptr<IHalPropValue>> & values)122 void onPropertyEvent(const std::vector<std::unique_ptr<IHalPropValue>>& values) override {
123 {
124 std::lock_guard<std::mutex> lockGuard(mLock);
125 for (auto& value : values) {
126 int32_t propId = value->getPropId();
127 mEvents[propId].push_back(value->clone());
128 }
129 }
130 mEventCond.notify_one();
131 }
132
onPropertySetError(const std::vector<HalPropError> & errors)133 void onPropertySetError([[maybe_unused]] const std::vector<HalPropError>& errors) override {
134 // Do nothing.
135 }
136
137 template <class Rep, class Period>
waitForExpectedEvents(int32_t propId,size_t expectedEvents,const std::chrono::duration<Rep,Period> & timeout)138 bool waitForExpectedEvents(int32_t propId, size_t expectedEvents,
139 const std::chrono::duration<Rep, Period>& timeout) {
140 std::unique_lock<std::mutex> uniqueLock(mLock);
141 return mEventCond.wait_for(uniqueLock, timeout, [this, propId, expectedEvents] {
142 ScopedLockAssertion lockAssertion(mLock);
143 return mEvents[propId].size() >= expectedEvents;
144 });
145 }
146
getEvents(int32_t propId)147 std::vector<std::unique_ptr<IHalPropValue>> getEvents(int32_t propId) {
148 std::lock_guard<std::mutex> lockGuard(mLock);
149 std::vector<std::unique_ptr<IHalPropValue>> events;
150 if (mEvents.find(propId) == mEvents.end()) {
151 return events;
152 }
153 for (const auto& eventPtr : mEvents[propId]) {
154 events.push_back(eventPtr->clone());
155 }
156 return events;
157 }
158
getEventTimestamps(int32_t propId)159 std::vector<int64_t> getEventTimestamps(int32_t propId) {
160 std::lock_guard<std::mutex> lockGuard(mLock);
161 std::vector<int64_t> timestamps;
162 if (mEvents.find(propId) == mEvents.end()) {
163 return timestamps;
164 }
165 for (const auto& valuePtr : mEvents[propId]) {
166 timestamps.push_back(valuePtr->getTimestamp());
167 }
168 return timestamps;
169 }
170
reset()171 void reset() {
172 std::lock_guard<std::mutex> lockGuard(mLock);
173 mEvents.clear();
174 }
175 };
176
177 class VtsHalAutomotiveTest : public testing::Test {
178 public:
179 void verifyAccessMode(int actualAccess, std::vector<VehiclePropertyAccess> expectedAccess);
180 void verifyGlobalAccessIsMaximalAreaAccessSubset(
181 int propertyLevelAccess,
182 const std::vector<std::unique_ptr<IHalAreaConfig>>& areaConfigs) const;
183 void verifyProperty(VehicleProperty propId, std::vector<VehiclePropertyAccess> accessModes,
184 VehiclePropertyChangeMode changeMode);
185 void testGetMinMaxSupportedValueForPropIdAreaId(int32_t propId,
186 const IHalAreaConfig& areaConfig,
187 bool minMaxValueRequired);
188 void testGetSupportedValuesListsForPropIdAreaId(int32_t propId,
189 const IHalAreaConfig& areaConfig,
190 bool supportedValuesRequired);
191
isBooleanGlobalProp(int32_t property)192 static bool isBooleanGlobalProp(int32_t property) {
193 return getPropertyType(property) == VehiclePropertyType::BOOLEAN &&
194 (property & toInt(VehicleArea::MASK)) == toInt(VehicleArea::GLOBAL);
195 }
196
197 protected:
198 std::shared_ptr<IVhalClient> mVhalClient;
199 std::shared_ptr<VtsVehicleCallback> mCallback;
200
201 bool checkIsSupported(int32_t propertyId);
202 void connectToVhal(const ServiceDescriptor& descriptor);
203
204 static bool isUnavailable(const VhalClientResult<std::unique_ptr<IHalPropValue>>& result);
205 static bool isResultOkayWithValue(
206 const VhalClientResult<std::unique_ptr<IHalPropValue>>& result, int32_t value);
207 };
208
checkIsSupported(int32_t propertyId)209 bool VtsHalAutomotiveTest::checkIsSupported(int32_t propertyId) {
210 auto result = mVhalClient->getPropConfigs({propertyId});
211 return result.ok();
212 }
213
connectToVhal(const ServiceDescriptor & descriptor)214 void VtsHalAutomotiveTest::connectToVhal(const ServiceDescriptor& descriptor) {
215 if (descriptor.isAidlService) {
216 mVhalClient = IVhalClient::tryCreateAidlClient(descriptor.name.c_str());
217 } else {
218 mVhalClient = IVhalClient::tryCreateHidlClient(descriptor.name.c_str());
219 }
220
221 ASSERT_NE(mVhalClient, nullptr) << "Failed to connect to VHAL";
222
223 mCallback = std::make_shared<VtsVehicleCallback>();
224 }
225
isResultOkayWithValue(const VhalClientResult<std::unique_ptr<IHalPropValue>> & result,int32_t value)226 bool VtsHalAutomotiveTest::isResultOkayWithValue(
227 const VhalClientResult<std::unique_ptr<IHalPropValue>>& result, int32_t value) {
228 return result.ok() && result.value() != nullptr &&
229 result.value()->getStatus() == VehiclePropertyStatus::AVAILABLE &&
230 result.value()->getInt32Values().size() == 1 &&
231 result.value()->getInt32Values()[0] == value;
232 }
233
isUnavailable(const VhalClientResult<std::unique_ptr<IHalPropValue>> & result)234 bool VtsHalAutomotiveTest::isUnavailable(
235 const VhalClientResult<std::unique_ptr<IHalPropValue>>& result) {
236 if (!result.ok()) {
237 return result.error().code() == ErrorCode::NOT_AVAILABLE_FROM_VHAL;
238 }
239 if (result.value() != nullptr &&
240 result.value()->getStatus() == VehiclePropertyStatus::UNAVAILABLE) {
241 return true;
242 }
243
244 return false;
245 }
246
verifyAccessMode(int actualAccess,std::vector<VehiclePropertyAccess> expectedAccess)247 void VtsHalAutomotiveTest::verifyAccessMode(int actualAccess,
248 std::vector<VehiclePropertyAccess> expectedAccess) {
249 if (actualAccess == toInt(VehiclePropertyAccess::NONE)) {
250 return;
251 }
252 EXPECT_THAT(expectedAccess,
253 ::testing::Contains(static_cast<VehiclePropertyAccess>(actualAccess)))
254 << "Invalid property access mode, not one of the allowed access modes";
255 }
256
verifyGlobalAccessIsMaximalAreaAccessSubset(int propertyLevelAccess,const std::vector<std::unique_ptr<IHalAreaConfig>> & areaConfigs) const257 void VtsHalAutomotiveTest::verifyGlobalAccessIsMaximalAreaAccessSubset(
258 int propertyLevelAccess,
259 const std::vector<std::unique_ptr<IHalAreaConfig>>& areaConfigs) const {
260 bool readOnlyPresent = false;
261 bool writeOnlyPresent = false;
262 bool readWritePresent = false;
263 int maximalAreaAccessSubset = toInt(VehiclePropertyAccess::NONE);
264 for (size_t i = 0; i < areaConfigs.size(); i++) {
265 int access = areaConfigs[i]->getAccess();
266 switch (access) {
267 case toInt(VehiclePropertyAccess::READ):
268 readOnlyPresent = true;
269 break;
270 case toInt(VehiclePropertyAccess::WRITE):
271 writeOnlyPresent = true;
272 break;
273 case toInt(VehiclePropertyAccess::READ_WRITE):
274 readWritePresent = true;
275 break;
276 default:
277 ASSERT_EQ(access, toInt(VehiclePropertyAccess::NONE))
278 << "Area access can be NONE only if global property access is also NONE";
279 return;
280 }
281 }
282
283 if (readOnlyPresent) {
284 ASSERT_FALSE(writeOnlyPresent)
285 << "Found both READ_ONLY and WRITE_ONLY access modes in area configs, which is not "
286 "supported";
287 maximalAreaAccessSubset = toInt(VehiclePropertyAccess::READ);
288 } else if (writeOnlyPresent) {
289 ASSERT_FALSE(readWritePresent) << "Found both WRITE_ONLY and READ_WRITE access modes in "
290 "area configs, which is not "
291 "supported";
292 maximalAreaAccessSubset = toInt(VehiclePropertyAccess::WRITE);
293 } else if (readWritePresent) {
294 maximalAreaAccessSubset = toInt(VehiclePropertyAccess::READ_WRITE);
295 }
296 ASSERT_EQ(propertyLevelAccess, maximalAreaAccessSubset) << StringPrintf(
297 "Expected global access to be equal to maximal area access subset %d, Instead got %d",
298 maximalAreaAccessSubset, propertyLevelAccess);
299 }
300
301 class VtsHalAutomotiveVehicleTargetTest : public VtsHalAutomotiveTest,
302 public testing::WithParamInterface<ServiceDescriptor> {
SetUp()303 virtual void SetUp() override { ASSERT_NO_FATAL_FAILURE(connectToVhal(GetParam())); }
304 };
305
306 class VtsHalAutomotivePropertyConfigTest
307 : public VtsHalAutomotiveTest,
308 public testing::WithParamInterface<std::tuple<PropertyConfigTestParam, ServiceDescriptor>> {
SetUp()309 virtual void SetUp() override {
310 ASSERT_NO_FATAL_FAILURE(connectToVhal(std::get<1>(GetParam())));
311 }
312 };
313
TEST_P(VtsHalAutomotiveVehicleTargetTest,useAidlBackend)314 TEST_P(VtsHalAutomotiveVehicleTargetTest, useAidlBackend) {
315 if (!mVhalClient->isAidlVhal()) {
316 GTEST_SKIP() << "AIDL backend is not available, HIDL backend is used instead";
317 }
318 }
319
TEST_P(VtsHalAutomotiveVehicleTargetTest,useHidlBackend)320 TEST_P(VtsHalAutomotiveVehicleTargetTest, useHidlBackend) {
321 if (mVhalClient->isAidlVhal()) {
322 GTEST_SKIP() << "AIDL backend is available, HIDL backend is not used";
323 }
324 }
325
326 // Test getAllPropConfigs() returns at least 1 property configs.
TEST_P(VtsHalAutomotiveVehicleTargetTest,getAllPropConfigs)327 TEST_P(VtsHalAutomotiveVehicleTargetTest, getAllPropConfigs) {
328 ALOGD("VtsHalAutomotiveVehicleTargetTest::getAllPropConfigs");
329
330 auto result = mVhalClient->getAllPropConfigs();
331
332 ASSERT_TRUE(result.ok()) << "Failed to get all property configs, error: "
333 << result.error().message();
334 ASSERT_GE(result.value().size(), 1u) << StringPrintf(
335 "Expect to get at least 1 property config, got %zu", result.value().size());
336 }
337
338 // Test getPropConfigs() can query properties returned by getAllPropConfigs.
TEST_P(VtsHalAutomotiveVehicleTargetTest,getPropConfigsWithValidProps)339 TEST_P(VtsHalAutomotiveVehicleTargetTest, getPropConfigsWithValidProps) {
340 ALOGD("VtsHalAutomotiveVehicleTargetTest::getRequiredPropConfigs");
341
342 std::vector<int32_t> properties;
343 auto result = mVhalClient->getAllPropConfigs();
344
345 ASSERT_TRUE(result.ok()) << "Failed to get all property configs, error: "
346 << result.error().message();
347 for (const auto& cfgPtr : result.value()) {
348 properties.push_back(cfgPtr->getPropId());
349 }
350
351 result = mVhalClient->getPropConfigs(properties);
352
353 ASSERT_TRUE(result.ok()) << "Failed to get required property config, error: "
354 << result.error().message();
355 ASSERT_EQ(result.value().size(), properties.size()) << StringPrintf(
356 "Expect to get exactly %zu configs, got %zu", properties.size(), result.value().size());
357 }
358
359 // Test getPropConfig() with an invalid propertyId returns an error code.
TEST_P(VtsHalAutomotiveVehicleTargetTest,getPropConfigsWithInvalidProp)360 TEST_P(VtsHalAutomotiveVehicleTargetTest, getPropConfigsWithInvalidProp) {
361 ALOGD("VtsHalAutomotiveVehicleTargetTest::getPropConfigsWithInvalidProp");
362
363 auto result = mVhalClient->getPropConfigs({kInvalidProp});
364
365 ASSERT_FALSE(result.ok()) << StringPrintf(
366 "Expect failure to get prop configs for invalid prop: %" PRId32, kInvalidProp);
367 ASSERT_NE(result.error().message(), "") << "Expect error message not to be empty";
368 }
369
370 // Test system property IDs returned by getPropConfigs() are defined in the VHAL property interface.
TEST_P(VtsHalAutomotiveVehicleTargetTest,testPropConfigs_onlyDefinedSystemPropertyIdsReturned)371 TEST_P(VtsHalAutomotiveVehicleTargetTest, testPropConfigs_onlyDefinedSystemPropertyIdsReturned) {
372 if (!mVhalClient->isAidlVhal()) {
373 GTEST_SKIP() << "Skip for HIDL VHAL because HAL interface run-time version is only"
374 << "introduced for AIDL";
375 }
376
377 auto result = mVhalClient->getAllPropConfigs();
378 ASSERT_TRUE(result.ok()) << "Failed to get all property configs, error: "
379 << result.error().message();
380
381 int32_t vhalVersion = mVhalClient->getRemoteInterfaceVersion();
382 const auto& configs = result.value();
383 for (size_t i = 0; i < configs.size(); i++) {
384 int32_t propId = configs[i]->getPropId();
385 if (!isSystemProp(propId)) {
386 continue;
387 }
388
389 std::string propName = propIdToString(propId);
390 auto it = VersionForVehicleProperty.find(static_cast<VehicleProperty>(propId));
391 bool found = (it != VersionForVehicleProperty.end());
392 EXPECT_TRUE(found) << "System Property: " << propName
393 << " is not defined in VHAL property interface";
394 if (!found) {
395 continue;
396 }
397 int32_t requiredVersion = it->second;
398 EXPECT_THAT(vhalVersion, Ge(requiredVersion))
399 << "System Property: " << propName << " requires VHAL version: " << requiredVersion
400 << ", but the current VHAL version"
401 << " is " << vhalVersion << ", must not be supported";
402 }
403 }
404
TEST_P(VtsHalAutomotiveVehicleTargetTest,testPropConfigs_globalAccessIsMaximalAreaAccessSubset)405 TEST_P(VtsHalAutomotiveVehicleTargetTest, testPropConfigs_globalAccessIsMaximalAreaAccessSubset) {
406 if (!mVhalClient->isAidlVhal()) {
407 GTEST_SKIP() << "Skip for HIDL VHAL because HAL interface run-time version is only"
408 << "introduced for AIDL";
409 }
410
411 auto result = mVhalClient->getAllPropConfigs();
412 ASSERT_TRUE(result.ok()) << "Failed to get all property configs, error: "
413 << result.error().message();
414
415 const auto& configs = result.value();
416 for (size_t i = 0; i < configs.size(); i++) {
417 verifyGlobalAccessIsMaximalAreaAccessSubset(configs[i]->getAccess(),
418 configs[i]->getAreaConfigs());
419 }
420 }
421
422 // Test get() return current value for properties.
TEST_P(VtsHalAutomotiveVehicleTargetTest,get)423 TEST_P(VtsHalAutomotiveVehicleTargetTest, get) {
424 ALOGD("VtsHalAutomotiveVehicleTargetTest::get");
425
426 int32_t propId = toInt(VehicleProperty::PERF_VEHICLE_SPEED);
427 if (!checkIsSupported(propId)) {
428 GTEST_SKIP() << "Property: " << propId << " is not supported, skip the test";
429 }
430 auto result = mVhalClient->getValueSync(*mVhalClient->createHalPropValue(propId));
431
432 ASSERT_TRUE(result.ok()) << StringPrintf("Failed to get value for property: %" PRId32
433 ", error: %s",
434 propId, result.error().message().c_str());
435 ASSERT_NE(result.value(), nullptr) << "Result value must not be null";
436 }
437
438 // Test get() with an invalid propertyId return an error codes.
TEST_P(VtsHalAutomotiveVehicleTargetTest,getInvalidProp)439 TEST_P(VtsHalAutomotiveVehicleTargetTest, getInvalidProp) {
440 ALOGD("VtsHalAutomotiveVehicleTargetTest::getInvalidProp");
441
442 auto result = mVhalClient->getValueSync(*mVhalClient->createHalPropValue(kInvalidProp));
443
444 ASSERT_FALSE(result.ok()) << StringPrintf(
445 "Expect failure to get property for invalid prop: %" PRId32, kInvalidProp);
446 }
447
448 // Test set() on read_write properties.
TEST_P(VtsHalAutomotiveVehicleTargetTest,setProp)449 TEST_P(VtsHalAutomotiveVehicleTargetTest, setProp) {
450 ALOGD("VtsHalAutomotiveVehicleTargetTest::setProp");
451
452 // skip hvac related properties
453 std::unordered_set<int32_t> hvacProps = {toInt(VehicleProperty::HVAC_DEFROSTER),
454 toInt(VehicleProperty::HVAC_AC_ON),
455 toInt(VehicleProperty::HVAC_MAX_AC_ON),
456 toInt(VehicleProperty::HVAC_MAX_DEFROST_ON),
457 toInt(VehicleProperty::HVAC_RECIRC_ON),
458 toInt(VehicleProperty::HVAC_DUAL_ON),
459 toInt(VehicleProperty::HVAC_AUTO_ON),
460 toInt(VehicleProperty::HVAC_POWER_ON),
461 toInt(VehicleProperty::HVAC_AUTO_RECIRC_ON),
462 toInt(VehicleProperty::HVAC_ELECTRIC_DEFROSTER_ON)};
463 auto result = mVhalClient->getAllPropConfigs();
464 ASSERT_TRUE(result.ok());
465
466 for (const auto& cfgPtr : result.value()) {
467 const IHalPropConfig& cfg = *cfgPtr;
468 int32_t propId = cfg.getPropId();
469 // test on boolean and writable property
470 bool isReadWrite = (cfg.getAccess() == toInt(VehiclePropertyAccess::READ_WRITE));
471 if (cfg.getAreaConfigSize() != 0 &&
472 cfg.getAreaConfigs()[0]->getAccess() != toInt(VehiclePropertyAccess::NONE)) {
473 isReadWrite = (cfg.getAreaConfigs()[0]->getAccess() ==
474 toInt(VehiclePropertyAccess::READ_WRITE));
475 }
476 if (isReadWrite && isBooleanGlobalProp(propId) && !hvacProps.count(propId)) {
477 auto propToGet = mVhalClient->createHalPropValue(propId);
478 auto getValueResult = mVhalClient->getValueSync(*propToGet);
479
480 if (isUnavailable(getValueResult)) {
481 ALOGW("getProperty for %" PRId32
482 " returns NOT_AVAILABLE, "
483 "skip testing setProp",
484 propId);
485 return;
486 }
487
488 ASSERT_TRUE(getValueResult.ok())
489 << StringPrintf("Failed to get value for property: %" PRId32 ", error: %s",
490 propId, getValueResult.error().message().c_str());
491 ASSERT_NE(getValueResult.value(), nullptr)
492 << StringPrintf("Result value must not be null for property: %" PRId32, propId);
493
494 const IHalPropValue& value = *getValueResult.value();
495 size_t intValueSize = value.getInt32Values().size();
496 ASSERT_EQ(intValueSize, 1u) << StringPrintf(
497 "Expect exactly 1 int value for boolean property: %" PRId32 ", got %zu", propId,
498 intValueSize);
499
500 int32_t setValue = value.getInt32Values()[0] == 1 ? 0 : 1;
501 auto propToSet = mVhalClient->createHalPropValue(propId);
502 propToSet->setInt32Values({setValue});
503 auto setValueResult = mVhalClient->setValueSync(*propToSet);
504
505 if (!setValueResult.ok() &&
506 setValueResult.error().code() == ErrorCode::NOT_AVAILABLE_FROM_VHAL) {
507 ALOGW("setProperty for %" PRId32
508 " returns NOT_AVAILABLE, "
509 "skip verifying getProperty returns the same value",
510 propId);
511 return;
512 }
513
514 ASSERT_TRUE(setValueResult.ok())
515 << StringPrintf("Failed to set value for property: %" PRId32 ", error: %s",
516 propId, setValueResult.error().message().c_str());
517 // Retry getting the value until we pass the timeout. getValue might not return
518 // the expected value immediately since setValue is async.
519 auto timeoutMillis = uptimeMillis() + kRetryGetPropAfterSetPropTimeoutMillis;
520
521 while (true) {
522 getValueResult = mVhalClient->getValueSync(*propToGet);
523 if (isResultOkayWithValue(getValueResult, setValue)) {
524 break;
525 }
526 if (uptimeMillis() >= timeoutMillis) {
527 // Reach timeout, the following assert should fail.
528 break;
529 }
530 // Sleep for 100ms between each getValueSync retry.
531 std::this_thread::sleep_for(std::chrono::milliseconds(100));
532 }
533
534 if (isUnavailable(getValueResult)) {
535 ALOGW("getProperty for %" PRId32
536 " returns NOT_AVAILABLE, "
537 "skip verifying the return value",
538 propId);
539 return;
540 }
541
542 ASSERT_TRUE(getValueResult.ok())
543 << StringPrintf("Failed to get value for property: %" PRId32 ", error: %s",
544 propId, getValueResult.error().message().c_str());
545 ASSERT_NE(getValueResult.value(), nullptr)
546 << StringPrintf("Result value must not be null for property: %" PRId32, propId);
547 ASSERT_EQ(getValueResult.value()->getInt32Values(), std::vector<int32_t>({setValue}))
548 << StringPrintf("Boolean value not updated after set for property: %" PRId32,
549 propId);
550 }
551 }
552 }
553
554 // Test set() on an read_only property.
TEST_P(VtsHalAutomotiveVehicleTargetTest,setNotWritableProp)555 TEST_P(VtsHalAutomotiveVehicleTargetTest, setNotWritableProp) {
556 ALOGD("VtsHalAutomotiveVehicleTargetTest::setNotWritableProp");
557
558 int32_t propId = toInt(VehicleProperty::PERF_VEHICLE_SPEED);
559 if (!checkIsSupported(propId)) {
560 GTEST_SKIP() << "Property: " << propId << " is not supported, skip the test";
561 }
562
563 auto getValueResult = mVhalClient->getValueSync(*mVhalClient->createHalPropValue(propId));
564 ASSERT_TRUE(getValueResult.ok())
565 << StringPrintf("Failed to get value for property: %" PRId32 ", error: %s", propId,
566 getValueResult.error().message().c_str());
567
568 auto setValueResult = mVhalClient->setValueSync(*getValueResult.value());
569
570 ASSERT_FALSE(setValueResult.ok()) << "Expect set a read-only value to fail";
571 ASSERT_EQ(setValueResult.error().code(), ErrorCode::ACCESS_DENIED_FROM_VHAL);
572 }
573
574 // Test get(), set() and getAllPropConfigs() on VehicleProperty::INVALID.
TEST_P(VtsHalAutomotiveVehicleTargetTest,getSetPropertyIdInvalid)575 TEST_P(VtsHalAutomotiveVehicleTargetTest, getSetPropertyIdInvalid) {
576 ALOGD("VtsHalAutomotiveVehicleTargetTest::getSetPropertyIdInvalid");
577
578 int32_t propId = toInt(VehicleProperty::INVALID);
579 auto getValueResult = mVhalClient->getValueSync(*mVhalClient->createHalPropValue(propId));
580 ASSERT_FALSE(getValueResult.ok()) << "Expect get on VehicleProperty::INVALID to fail";
581 ASSERT_EQ(getValueResult.error().code(), ErrorCode::INVALID_ARG);
582
583 auto propToSet = mVhalClient->createHalPropValue(propId);
584 propToSet->setInt32Values({0});
585 auto setValueResult = mVhalClient->setValueSync(*propToSet);
586 ASSERT_FALSE(setValueResult.ok()) << "Expect set on VehicleProperty::INVALID to fail";
587 ASSERT_EQ(setValueResult.error().code(), ErrorCode::INVALID_ARG);
588
589 auto result = mVhalClient->getAllPropConfigs();
590 ASSERT_TRUE(result.ok());
591 for (const auto& cfgPtr : result.value()) {
592 const IHalPropConfig& cfg = *cfgPtr;
593 ASSERT_FALSE(cfg.getPropId() == propId) << "Expect VehicleProperty::INVALID to not be "
594 "included in propConfigs";
595 }
596 }
597
598 // Test subscribe() and unsubscribe().
TEST_P(VtsHalAutomotiveVehicleTargetTest,subscribeAndUnsubscribe)599 TEST_P(VtsHalAutomotiveVehicleTargetTest, subscribeAndUnsubscribe) {
600 ALOGD("VtsHalAutomotiveVehicleTargetTest::subscribeAndUnsubscribe");
601
602 int32_t propId = toInt(VehicleProperty::PERF_VEHICLE_SPEED);
603 if (!checkIsSupported(propId)) {
604 GTEST_SKIP() << "Property: " << propId << " is not supported, skip the test";
605 }
606
607 auto propConfigsResult = mVhalClient->getPropConfigs({propId});
608
609 ASSERT_TRUE(propConfigsResult.ok()) << "Failed to get property config for PERF_VEHICLE_SPEED: "
610 << "error: " << propConfigsResult.error().message();
611 ASSERT_EQ(propConfigsResult.value().size(), 1u)
612 << "Expect to return 1 config for PERF_VEHICLE_SPEED";
613 auto& propConfig = propConfigsResult.value()[0];
614 float minSampleRate = propConfig->getMinSampleRate();
615 float maxSampleRate = propConfig->getMaxSampleRate();
616
617 if (minSampleRate < 1) {
618 GTEST_SKIP() << "Sample rate for vehicle speed < 1 times/sec, skip test since it would "
619 "take too long";
620 }
621
622 auto client = mVhalClient->getSubscriptionClient(mCallback);
623 ASSERT_NE(client, nullptr) << "Failed to get subscription client";
624
625 auto result = client->subscribe({{.propId = propId, .sampleRate = minSampleRate}});
626
627 ASSERT_TRUE(result.ok()) << StringPrintf("Failed to subscribe to property: %" PRId32
628 ", error: %s",
629 propId, result.error().message().c_str());
630
631 if (mVhalClient->isAidlVhal()) {
632 // Skip checking timestamp for HIDL because the behavior for sample rate and timestamp is
633 // only specified clearly for AIDL.
634
635 // Timeout is 2 seconds, which gives a 1 second buffer.
636 ASSERT_TRUE(mCallback->waitForExpectedEvents(propId, std::floor(minSampleRate),
637 std::chrono::seconds(2)))
638 << "Didn't get enough events for subscribing to minSampleRate";
639 }
640
641 result = client->subscribe({{.propId = propId, .sampleRate = maxSampleRate}});
642
643 ASSERT_TRUE(result.ok()) << StringPrintf("Failed to subscribe to property: %" PRId32
644 ", error: %s",
645 propId, result.error().message().c_str());
646
647 if (mVhalClient->isAidlVhal()) {
648 ASSERT_TRUE(mCallback->waitForExpectedEvents(propId, std::floor(maxSampleRate),
649 std::chrono::seconds(2)))
650 << "Didn't get enough events for subscribing to maxSampleRate";
651
652 std::unordered_set<int64_t> timestamps;
653 // Event event should have a different timestamp.
654 for (const int64_t& eventTimestamp : mCallback->getEventTimestamps(propId)) {
655 ASSERT_TRUE(timestamps.find(eventTimestamp) == timestamps.end())
656 << "two events for the same property must not have the same timestamp";
657 timestamps.insert(eventTimestamp);
658 }
659 }
660
661 result = client->unsubscribe({propId});
662 ASSERT_TRUE(result.ok()) << StringPrintf("Failed to unsubscribe to property: %" PRId32
663 ", error: %s",
664 propId, result.error().message().c_str());
665
666 mCallback->reset();
667 ASSERT_FALSE(mCallback->waitForExpectedEvents(propId, 10, std::chrono::seconds(1)))
668 << "Expect not to get events after unsubscription";
669 }
670
isVariableUpdateRateSupported(const std::unique_ptr<IHalPropConfig> & config,int32_t areaId)671 bool isVariableUpdateRateSupported(const std::unique_ptr<IHalPropConfig>& config, int32_t areaId) {
672 for (const auto& areaConfigPtr : config->getAreaConfigs()) {
673 if (areaConfigPtr->getAreaId() == areaId &&
674 areaConfigPtr->isVariableUpdateRateSupported()) {
675 return true;
676 }
677 }
678 return false;
679 }
680
681 // Test subscribe with variable update rate enabled if supported.
TEST_P(VtsHalAutomotiveVehicleTargetTest,subscribe_enableVurIfSupported)682 TEST_P(VtsHalAutomotiveVehicleTargetTest, subscribe_enableVurIfSupported) {
683 ALOGD("VtsHalAutomotiveVehicleTargetTest::subscribe_enableVurIfSupported");
684
685 int32_t propId = toInt(VehicleProperty::PERF_VEHICLE_SPEED);
686 if (!checkIsSupported(propId)) {
687 GTEST_SKIP() << "Property: " << propId << " is not supported, skip the test";
688 }
689 if (!mVhalClient->isAidlVhal()) {
690 GTEST_SKIP() << "Variable update rate is only supported by AIDL VHAL";
691 }
692
693 auto propConfigsResult = mVhalClient->getPropConfigs({propId});
694
695 ASSERT_TRUE(propConfigsResult.ok()) << "Failed to get property config for PERF_VEHICLE_SPEED: "
696 << "error: " << propConfigsResult.error().message();
697 ASSERT_EQ(propConfigsResult.value().size(), 1u)
698 << "Expect to return 1 config for PERF_VEHICLE_SPEED";
699 auto& propConfig = propConfigsResult.value()[0];
700 float maxSampleRate = propConfig->getMaxSampleRate();
701 if (maxSampleRate < 1) {
702 GTEST_SKIP() << "Sample rate for vehicle speed < 1 times/sec, skip test since it would "
703 "take too long";
704 }
705 // PERF_VEHICLE_SPEED is a global property, so areaId is 0.
706 if (!isVariableUpdateRateSupported(propConfig, /* areaId= */ 0)) {
707 GTEST_SKIP() << "Variable update rate is not supported for PERF_VEHICLE_SPEED, "
708 << "skip testing";
709 }
710
711 // Subscribe to PERF_VEHICLE_SPEED using the max sample rate.
712 auto client = mVhalClient->getSubscriptionClient(mCallback);
713 ASSERT_NE(client, nullptr) << "Failed to get subscription client";
714 SubscribeOptionsBuilder builder(propId);
715 // By default variable update rate is true.
716 builder.setSampleRate(maxSampleRate);
717 auto option = builder.build();
718
719 auto result = client->subscribe({option});
720
721 ASSERT_TRUE(result.ok()) << StringPrintf("Failed to subscribe to property: %" PRId32
722 ", error: %s",
723 propId, result.error().message().c_str());
724
725 // Sleep for 1 seconds to wait for more possible events to arrive.
726 std::this_thread::sleep_for(std::chrono::seconds(1));
727
728 client->unsubscribe({propId});
729
730 auto events = mCallback->getEvents(propId);
731 if (events.size() <= 1) {
732 // We received 0 or 1 event, the value is not changing so nothing to check here.
733 // If all VHAL clients are subscribing to PERF_VEHICLE_SPEED with VUR on, then we
734 // will receive 0 event. If there are other VHAL clients subscribing to PERF_VEHICLE_SPEED
735 // with VUR off, then we will receive 1 event which is the initial value.
736 return;
737 }
738
739 // Sort the values by the timestamp.
740 std::map<int64_t, float> valuesByTimestamp;
741 for (size_t i = 0; i < events.size(); i++) {
742 valuesByTimestamp[events[i]->getTimestamp()] = events[i]->getFloatValues()[0];
743 }
744
745 size_t i = 0;
746 float previousValue;
747 for (const auto& [_, value] : valuesByTimestamp) {
748 if (i != 0) {
749 ASSERT_FALSE(value != previousValue) << "received duplicate value: " << value
750 << " when variable update rate is true";
751 }
752 previousValue = value;
753 i++;
754 }
755 }
756
757 // Test subscribe() with an invalid property.
TEST_P(VtsHalAutomotiveVehicleTargetTest,subscribeInvalidProp)758 TEST_P(VtsHalAutomotiveVehicleTargetTest, subscribeInvalidProp) {
759 ALOGD("VtsHalAutomotiveVehicleTargetTest::subscribeInvalidProp");
760
761 std::vector<SubscribeOptions> options = {
762 SubscribeOptions{.propId = kInvalidProp, .sampleRate = 10.0}};
763
764 auto client = mVhalClient->getSubscriptionClient(mCallback);
765 ASSERT_NE(client, nullptr) << "Failed to get subscription client";
766
767 auto result = client->subscribe(options);
768
769 ASSERT_FALSE(result.ok()) << StringPrintf("Expect subscribing to property: %" PRId32 " to fail",
770 kInvalidProp);
771 }
772
773 // Test the timestamp returned in GetValues results is the timestamp when the value is retrieved.
TEST_P(VtsHalAutomotiveVehicleTargetTest,testGetValuesTimestampAIDL)774 TEST_P(VtsHalAutomotiveVehicleTargetTest, testGetValuesTimestampAIDL) {
775 if (!mVhalClient->isAidlVhal()) {
776 GTEST_SKIP() << "Skip checking timestamp for HIDL because the behavior is only specified "
777 "for AIDL";
778 }
779
780 int32_t propId = toInt(VehicleProperty::PARKING_BRAKE_ON);
781 if (!checkIsSupported(propId)) {
782 GTEST_SKIP() << "Property: " << propId << " is not supported, skip the test";
783 }
784 auto prop = mVhalClient->createHalPropValue(propId);
785
786 auto result = mVhalClient->getValueSync(*prop);
787
788 ASSERT_TRUE(result.ok()) << StringPrintf("Failed to get value for property: %" PRId32
789 ", error: %s",
790 propId, result.error().message().c_str());
791 ASSERT_NE(result.value(), nullptr) << "Result value must not be null";
792 ASSERT_EQ(result.value()->getInt32Values().size(), 1u) << "Result must contain 1 int value";
793
794 bool parkBrakeOnValue1 = (result.value()->getInt32Values()[0] == 1);
795 int64_t timestampValue1 = result.value()->getTimestamp();
796
797 result = mVhalClient->getValueSync(*prop);
798
799 ASSERT_TRUE(result.ok()) << StringPrintf("Failed to get value for property: %" PRId32
800 ", error: %s",
801 propId, result.error().message().c_str());
802 ASSERT_NE(result.value(), nullptr) << "Result value must not be null";
803 ASSERT_EQ(result.value()->getInt32Values().size(), 1u) << "Result must contain 1 int value";
804
805 bool parkBarkeOnValue2 = (result.value()->getInt32Values()[0] == 1);
806 int64_t timestampValue2 = result.value()->getTimestamp();
807
808 if (parkBarkeOnValue2 == parkBrakeOnValue1) {
809 ASSERT_EQ(timestampValue2, timestampValue1)
810 << "getValue result must contain a timestamp updated when the value was updated, if"
811 "the value does not change, expect the same timestamp";
812 } else {
813 ASSERT_GT(timestampValue2, timestampValue1)
814 << "getValue result must contain a timestamp updated when the value was updated, if"
815 "the value changes, expect the newer value has a larger timestamp";
816 }
817 }
818
verifyRawPropValues(const RawPropValues & rawPropValues,VehiclePropertyType propertyType)819 void verifyRawPropValues(const RawPropValues& rawPropValues, VehiclePropertyType propertyType) {
820 switch (propertyType) {
821 case VehiclePropertyType::INT32:
822 ASSERT_THAT(rawPropValues.int32Values, ::testing::SizeIs(1))
823 << "int32Values field must contain exactly one element for INT32 type";
824 break;
825 case VehiclePropertyType::FLOAT:
826 ASSERT_THAT(rawPropValues.floatValues, ::testing::SizeIs(1))
827 << "floatValues field must contain exactly one element for FLOAT type";
828 break;
829 case VehiclePropertyType::INT64:
830 ASSERT_THAT(rawPropValues.int64Values, ::testing::SizeIs(1))
831 << "int64Values field must contain exactly one element for INT64 type";
832 break;
833 default:
834 // We do not check for other types.
835 break;
836 }
837 }
838
testGetMinMaxSupportedValueForPropIdAreaId(int32_t propId,const IHalAreaConfig & areaConfig,bool minMaxValueRequired)839 void VtsHalAutomotiveTest::testGetMinMaxSupportedValueForPropIdAreaId(
840 int32_t propId, const IHalAreaConfig& areaConfig, bool minMaxValueRequired) {
841 int32_t areaId = areaConfig.getAreaId();
842 VehiclePropertyType propertyType = getPropertyType(propId);
843 std::optional<HasSupportedValueInfo> maybeHasSupportedValueInfo =
844 areaConfig.getHasSupportedValueInfo();
845 if (!maybeHasSupportedValueInfo.has_value()) {
846 return;
847 }
848 if (!maybeHasSupportedValueInfo->hasMinSupportedValue &&
849 !maybeHasSupportedValueInfo->hasMaxSupportedValue) {
850 return;
851 }
852 VhalClientResult<std::vector<MinMaxSupportedValueResult>> result =
853 mVhalClient->getMinMaxSupportedValue({PropIdAreaId{
854 .propId = propId,
855 .areaId = areaId,
856 }});
857 ASSERT_RESULT_OK(result)
858 << "getMinMaxSupportedValue must return okay result if hasMaxSupportedValue "
859 << " or hasMaxSupportedValue is true";
860 ASSERT_THAT(*result, ::testing::SizeIs(1))
861 << "getMinMaxSupportedValue result list size must be 1 for 1 request";
862 const MinMaxSupportedValueResult& individualResult = (*result)[0];
863 if (minMaxValueRequired) {
864 ASSERT_EQ(individualResult.status, StatusCode::OK)
865 << "getMinMaxSupportedValue must return okay status if min/max value is required";
866 }
867 if (individualResult.status != StatusCode::OK) {
868 return;
869 }
870 bool hasMinValue = individualResult.minSupportedValue.has_value();
871 bool hasMaxValue = individualResult.maxSupportedValue.has_value();
872 if (maybeHasSupportedValueInfo->hasMinSupportedValue) {
873 ASSERT_TRUE(hasMinValue)
874 << "minSupportedValue field must not be null if hasMinSupportedValue is true";
875 }
876 if (maybeHasSupportedValueInfo->hasMaxSupportedValue) {
877 ASSERT_TRUE(hasMaxValue)
878 << "minSupportedValue field must not be null if hasMinSupportedValue is true";
879 }
880 if (hasMinValue) {
881 ASSERT_NO_FATAL_FAILURE(
882 verifyRawPropValues(*individualResult.minSupportedValue, propertyType))
883 << "MinMaxSupportedValueResult.minSupportedValue is not a valid RawPropValues for "
884 << "the property type, value: " << (individualResult.minSupportedValue)->toString();
885 }
886 if (hasMaxValue) {
887 ASSERT_NO_FATAL_FAILURE(
888 verifyRawPropValues(*individualResult.maxSupportedValue, propertyType))
889 << "MinMaxSupportedValueResult.maxSupportedValue is not a valid RawPropValues for "
890 << "the property type, value: " << (individualResult.maxSupportedValue)->toString();
891 }
892 if (hasMinValue && hasMaxValue) {
893 int32_t minInt32Value;
894 int32_t maxInt32Value;
895 float minFloatValue;
896 float maxFloatValue;
897 int64_t minInt64Value;
898 int64_t maxInt64Value;
899 switch (propertyType) {
900 case VehiclePropertyType::INT32:
901 minInt32Value = (individualResult.minSupportedValue)->int32Values[0];
902 maxInt32Value = (individualResult.maxSupportedValue)->int32Values[0];
903 ASSERT_LE(minInt32Value, maxInt32Value)
904 << "minSupportedValue must be less or equal to maxSupportedValue";
905 break;
906 case VehiclePropertyType::FLOAT:
907 minFloatValue = (individualResult.minSupportedValue)->floatValues[0];
908 maxFloatValue = (individualResult.maxSupportedValue)->floatValues[0];
909 ASSERT_LE(minFloatValue, maxFloatValue)
910 << "minSupportedValue must be less or equal to maxSupportedValue";
911 break;
912 case VehiclePropertyType::INT64:
913 minInt64Value = (individualResult.minSupportedValue)->int64Values[0];
914 maxInt64Value = (individualResult.maxSupportedValue)->int64Values[0];
915 ASSERT_LE(minInt64Value, maxInt64Value)
916 << "minSupportedValue must be less or equal to maxSupportedValue";
917 break;
918 default:
919 // This must not happen since we already checked this condition in
920 // verifyPropertyConfigMinMaxValue
921 FAIL() << "minSupportedValue or maxSupportedValue must only be specified for "
922 "INT32, INT64 or FLOAT type property";
923 break;
924 }
925 }
926 }
927
928 // Test the getMinMaxSupportedValue API. We use this one test case to cover all properties that
929 // may support this API.
TEST_P(VtsHalAutomotiveVehicleTargetTest,testGetMinMaxSupportedValue)930 TEST_P(VtsHalAutomotiveVehicleTargetTest, testGetMinMaxSupportedValue) {
931 if (!mVhalClient->isAidlVhal() || mVhalClient->getRemoteInterfaceVersion() < 4) {
932 GTEST_SKIP() << "Skip checking getMinMaxSupportedValue because the behavior is not "
933 "supported for current VHAL version";
934 }
935
936 auto configsResult = mVhalClient->getAllPropConfigs();
937 ASSERT_TRUE(configsResult.ok())
938 << "Failed to get all property configs, error: " << configsResult.error().message();
939
940 for (const auto& cfgPtr : configsResult.value()) {
941 int32_t propId = cfgPtr->getPropId();
942 bool minMaxValueRequired = false;
943 std::unordered_set<std::string> annotations;
944 auto it = AnnotationsForVehicleProperty.find(static_cast<VehicleProperty>(propId));
945 if (it != AnnotationsForVehicleProperty.end()) {
946 annotations = it->second;
947 }
948 if (annotations.find(ANNOTATION_REQUIRE_MIN_MAX_VALUE) != annotations.end()) {
949 minMaxValueRequired = true;
950 }
951 const std::vector<std::unique_ptr<IHalAreaConfig>>& areaConfigs = cfgPtr->getAreaConfigs();
952 for (const auto& areaCfgPtr : areaConfigs) {
953 EXPECT_NO_FATAL_FAILURE(testGetMinMaxSupportedValueForPropIdAreaId(propId, *areaCfgPtr,
954 minMaxValueRequired))
955 << "test getMinMaxSupportedValue failed for property: "
956 << propIdToString(propId) << ", areaId: " << areaCfgPtr->getAreaId();
957 }
958 }
959 }
960
testGetSupportedValuesListsForPropIdAreaId(int32_t propId,const IHalAreaConfig & areaConfig,bool supportedValuesRequired)961 void VtsHalAutomotiveTest::testGetSupportedValuesListsForPropIdAreaId(
962 int32_t propId, const IHalAreaConfig& areaConfig, bool supportedValuesRequired) {
963 int32_t areaId = areaConfig.getAreaId();
964 VehiclePropertyType propertyType = getPropertyType(propId);
965 std::optional<HasSupportedValueInfo> maybeHasSupportedValueInfo =
966 areaConfig.getHasSupportedValueInfo();
967 if (!maybeHasSupportedValueInfo.has_value()) {
968 return;
969 }
970 if (!maybeHasSupportedValueInfo->hasSupportedValuesList) {
971 return;
972 }
973 VhalClientResult<std::vector<SupportedValuesListResult>> result =
974 mVhalClient->getSupportedValuesLists({PropIdAreaId{
975 .propId = propId,
976 .areaId = areaId,
977 }});
978 ASSERT_RESULT_OK(result)
979 << "getSupportedValuesLists must return okay result if hasSupportedValuesList is true";
980 ASSERT_THAT(*result, ::testing::SizeIs(1))
981 << "getSupportedValuesLists result list size must be 1 for 1 request";
982 const SupportedValuesListResult& individualResult = (*result)[0];
983 if (supportedValuesRequired) {
984 ASSERT_EQ(individualResult.status, StatusCode::OK)
985 << "getSupportedValuesLists must return okay status if supported values are "
986 "required";
987 }
988 if (individualResult.status != StatusCode::OK) {
989 return;
990 }
991 ASSERT_TRUE(individualResult.supportedValuesList.has_value())
992 << "supportedValuesList field must not be null if hasSupportedValuesList is true";
993 const std::vector<std::optional<RawPropValues>>& supportedValuesList =
994 individualResult.supportedValuesList.value();
995 if (supportedValuesRequired) {
996 ASSERT_THAT(supportedValuesList, ::testing::Not(::testing::IsEmpty()))
997 << "supportedValuesList must not be empty if supported values are required";
998 }
999 for (const std::optional<RawPropValues>& supportedValue : supportedValuesList) {
1000 ASSERT_TRUE(supportedValue.has_value())
1001 << "Each item in supportedValuesList must not be null";
1002 ASSERT_NO_FATAL_FAILURE(verifyRawPropValues(*supportedValue, propertyType))
1003 << "one of supported value is not a valid RawPropValues for "
1004 << "the property type, value: " << supportedValue->toString();
1005 }
1006 }
1007
1008 // Test the getSupportedValues API. We use this one test case to cover all properties that
1009 // may support this API.
TEST_P(VtsHalAutomotiveVehicleTargetTest,testGetSupportedValuesLists)1010 TEST_P(VtsHalAutomotiveVehicleTargetTest, testGetSupportedValuesLists) {
1011 if (!mVhalClient->isAidlVhal() || mVhalClient->getRemoteInterfaceVersion() < 4) {
1012 GTEST_SKIP() << "Skip checking getSupportedValuesLists because the behavior is not "
1013 "supported for current VHAL version";
1014 }
1015
1016 auto configsResult = mVhalClient->getAllPropConfigs();
1017 ASSERT_TRUE(configsResult.ok())
1018 << "Failed to get all property configs, error: " << configsResult.error().message();
1019
1020 for (const auto& cfgPtr : configsResult.value()) {
1021 int32_t propId = cfgPtr->getPropId();
1022 bool supportedValuesRequired = false;
1023 std::unordered_set<std::string> annotations;
1024 auto it = AnnotationsForVehicleProperty.find(static_cast<VehicleProperty>(propId));
1025 if (it != AnnotationsForVehicleProperty.end()) {
1026 annotations = it->second;
1027 }
1028 if (annotations.find(ANNOTATION_REQUIRE_SUPPORTED_VALUES) != annotations.end()) {
1029 supportedValuesRequired = true;
1030 }
1031 const std::vector<std::unique_ptr<IHalAreaConfig>>& areaConfigs = cfgPtr->getAreaConfigs();
1032 for (const auto& areaCfgPtr : areaConfigs) {
1033 EXPECT_NO_FATAL_FAILURE(testGetSupportedValuesListsForPropIdAreaId(
1034 propId, *areaCfgPtr, supportedValuesRequired))
1035 << "test getSupportedValues failed for property: " << propIdToString(propId)
1036 << ", areaId: " << areaCfgPtr->getAreaId();
1037 }
1038 }
1039 }
1040
verifyPropertyConfigMinMaxValue(const IHalPropConfig * config,VehiclePropertyType propertyType)1041 void verifyPropertyConfigMinMaxValue(const IHalPropConfig* config,
1042 VehiclePropertyType propertyType) {
1043 for (const auto& areaConfig : config->getAreaConfigs()) {
1044 std::optional<HasSupportedValueInfo> maybeHasSupportedValueInfo =
1045 areaConfig->getHasSupportedValueInfo();
1046 if (areaConfig->getMinInt32Value() != 0 || areaConfig->getMaxInt32Value() != 0) {
1047 EXPECT_EQ(propertyType, VehiclePropertyType::INT32)
1048 << "minInt32Value and maxInt32Value must not be specified for INT32 type "
1049 "property";
1050 EXPECT_THAT(areaConfig->getMinInt32Value(),
1051 ::testing::Le(areaConfig->getMaxInt32Value()))
1052 << "minInt32Value must be less or equal to maxInt32Value";
1053 if (maybeHasSupportedValueInfo.has_value()) {
1054 EXPECT_TRUE(maybeHasSupportedValueInfo->hasMinSupportedValue)
1055 << "HasSupportedValueInfo.hasMinSupportedValue must be true because"
1056 "minInt32Value is specified in VehicleAreaConfig";
1057 EXPECT_TRUE(maybeHasSupportedValueInfo->hasMaxSupportedValue)
1058 << "HasSupportedValueInfo.hasMaxSupportedValue must be true because"
1059 "maxInt32Value is specified in VehicleAreaConfig";
1060 }
1061 }
1062 if (areaConfig->getMinFloatValue() != 0 || areaConfig->getMaxFloatValue() != 0) {
1063 EXPECT_EQ(propertyType, VehiclePropertyType::FLOAT)
1064 << "minFloatValue and maxFloatValue must not be specified for FLOAT type "
1065 "property";
1066 EXPECT_THAT(areaConfig->getMinFloatValue(),
1067 ::testing::Le(areaConfig->getMaxFloatValue()))
1068 << "minFloatValue must be less or equal to maxFloatValue";
1069 if (maybeHasSupportedValueInfo.has_value()) {
1070 EXPECT_TRUE(maybeHasSupportedValueInfo->hasMinSupportedValue)
1071 << "HasSupportedValueInfo.hasMinSupportedValue must be true because"
1072 "minFloatValue is specified in VehicleAreaConfig";
1073 EXPECT_TRUE(maybeHasSupportedValueInfo->hasMaxSupportedValue)
1074 << "HasSupportedValueInfo.hasMaxSupportedValue must be true because"
1075 "maxFloatValue is specified in VehicleAreaConfig";
1076 }
1077 }
1078 if (areaConfig->getMinInt64Value() != 0 || areaConfig->getMaxInt64Value() != 0) {
1079 EXPECT_EQ(propertyType, VehiclePropertyType::INT64)
1080 << "minInt64Value and maxInt64Value must not be specified for INT64 type "
1081 "property";
1082 EXPECT_THAT(areaConfig->getMinInt64Value(),
1083 ::testing::Le(areaConfig->getMaxInt64Value()))
1084 << "minInt64Value must be less or equal to maxInt64Value";
1085 if (maybeHasSupportedValueInfo.has_value()) {
1086 EXPECT_TRUE(maybeHasSupportedValueInfo->hasMinSupportedValue)
1087 << "HasSupportedValueInfo.hasMinSupportedValue must be true because"
1088 "minInt64Value is specified in VehicleAreaConfig";
1089 EXPECT_TRUE(maybeHasSupportedValueInfo->hasMaxSupportedValue)
1090 << "HasSupportedValueInfo.hasMaxSupportedValue must be true because"
1091 "maxInt64Value is specified in VehicleAreaConfig";
1092 }
1093 }
1094 if (maybeHasSupportedValueInfo.has_value() &&
1095 (maybeHasSupportedValueInfo->hasMinSupportedValue ||
1096 maybeHasSupportedValueInfo->hasMaxSupportedValue)) {
1097 EXPECT_THAT(propertyType,
1098 ::testing::AnyOf(VehiclePropertyType::INT32, VehiclePropertyType::INT64,
1099 VehiclePropertyType::FLOAT))
1100 << "HasSupportedValueInfo.hasMinSupportedValue and "
1101 "HasSupportedValueInfo.hasMaxSupportedValue is only allowed to be set to "
1102 "true "
1103 "for INT32, INT64 or FLOAT type property";
1104 }
1105 }
1106 }
1107
verifyPropertyConfigRequireMinMaxValue(const IHalPropConfig * config,VehiclePropertyType propertyType)1108 void verifyPropertyConfigRequireMinMaxValue(const IHalPropConfig* config,
1109 VehiclePropertyType propertyType) {
1110 for (const auto& areaConfig : config->getAreaConfigs()) {
1111 switch (propertyType) {
1112 case VehiclePropertyType::INT32:
1113 EXPECT_FALSE(areaConfig->getMinInt32Value() == 0 &&
1114 areaConfig->getMaxInt32Value() == 0)
1115 << "minInt32Value and maxInt32Value must not both be 0 because "
1116 "min and max value is required for this property";
1117 break;
1118 case VehiclePropertyType::FLOAT:
1119 EXPECT_FALSE(areaConfig->getMinFloatValue() == 0 &&
1120 areaConfig->getMaxFloatValue() == 0)
1121 << "minFloatValue and maxFloatValue must not both be 0 because "
1122 "min and max value is required for this property";
1123 break;
1124 case VehiclePropertyType::INT64:
1125 EXPECT_FALSE(areaConfig->getMinInt64Value() == 0 &&
1126 areaConfig->getMaxInt64Value() == 0)
1127 << "minInt64Value and maxInt64Value must not both be 0 because "
1128 "min and max value is required for this property";
1129 break;
1130 default:
1131 // Do nothing.
1132 break;
1133 }
1134
1135 std::optional<HasSupportedValueInfo> maybeHasSupportedValueInfo =
1136 areaConfig->getHasSupportedValueInfo();
1137 if (maybeHasSupportedValueInfo.has_value()) {
1138 EXPECT_TRUE(maybeHasSupportedValueInfo->hasMinSupportedValue)
1139 << "HasSupportedValueInfo.hasMinSupportedValue must be true because"
1140 "min and max value is required for this property";
1141 EXPECT_TRUE(maybeHasSupportedValueInfo->hasMaxSupportedValue)
1142 << "HasSupportedValueInfo.hasMaxSupportedValue must be true because"
1143 "min and max value is required for this property";
1144 }
1145 }
1146 }
1147
verifyPropertyConfigRequireSupportedValues(const IHalPropConfig * config,const std::unordered_set<std::string> & annotations)1148 void verifyPropertyConfigRequireSupportedValues(
1149 const IHalPropConfig* config, const std::unordered_set<std::string>& annotations) {
1150 bool supportedValuesInConfig =
1151 (annotations.find(ANNOTATION_SUPPORTED_VALUES_IN_CONFIG) != annotations.end());
1152 if (supportedValuesInConfig) {
1153 const std::vector<int32_t>& configArray = config->getConfigArray();
1154 EXPECT_THAT(configArray, Not(::testing::IsEmpty()))
1155 << "Config array must not be empty because supported values list must be specified"
1156 << " by the config array";
1157 }
1158
1159 for (const auto& areaConfig : config->getAreaConfigs()) {
1160 std::optional<HasSupportedValueInfo> maybeHasSupportedValueInfo =
1161 areaConfig->getHasSupportedValueInfo();
1162 if (maybeHasSupportedValueInfo.has_value()) {
1163 EXPECT_TRUE(maybeHasSupportedValueInfo->hasSupportedValuesList)
1164 << "HasSupportedValueInfo.hasSupportedValuesList must be true because"
1165 "supported values list is required for this property";
1166 }
1167 }
1168 }
1169
verifyPropertyConfigDataEnum(const IHalPropConfig * config)1170 void verifyPropertyConfigDataEnum(const IHalPropConfig* config) {
1171 for (const auto& areaConfig : config->getAreaConfigs()) {
1172 std::optional<std::vector<int64_t>> maybeSupportedEnumValues =
1173 areaConfig->getSupportedEnumValues();
1174 if (!maybeSupportedEnumValues.has_value()) {
1175 continue;
1176 }
1177 std::optional<HasSupportedValueInfo> maybeHasSupportedValueInfo =
1178 areaConfig->getHasSupportedValueInfo();
1179 const std::vector<int64_t>& supportedEnumValues = *maybeSupportedEnumValues;
1180 if (!supportedEnumValues.empty() && maybeHasSupportedValueInfo.has_value()) {
1181 EXPECT_TRUE(maybeHasSupportedValueInfo->hasSupportedValuesList)
1182 << "HasSupportedValueInfo.hasSupportedValuesList must be true because"
1183 "supported enum values is not empty";
1184 }
1185
1186 if (!supportedEnumValues.empty()) {
1187 std::unordered_set<int64_t> allowedEnumValues = getSupportedEnumValuesForProperty(
1188 static_cast<VehicleProperty>(config->getPropId()));
1189 EXPECT_THAT(supportedEnumValues, ::testing::IsSubsetOf(allowedEnumValues))
1190 << "Supported enum values must be part of defined enum type";
1191 }
1192 }
1193 }
1194
1195 /**
1196 * Verifies that each property's property config is consistent with the requirement
1197 * documented in VehicleProperty.aidl.
1198 */
TEST_P(VtsHalAutomotivePropertyConfigTest,verifyPropertyConfig)1199 TEST_P(VtsHalAutomotivePropertyConfigTest, verifyPropertyConfig) {
1200 const PropertyConfigTestParam& param = std::get<0>(GetParam());
1201 int expectedPropId = toInt(param.propId);
1202 int expectedChangeMode = toInt(param.changeMode);
1203
1204 auto result = mVhalClient->getAllPropConfigs();
1205 ASSERT_TRUE(result.ok()) << "Failed to get all property configs, error: "
1206 << result.error().message();
1207
1208 // Check if property is implemented by getting all configs and looking to see if the expected
1209 // property id is in that list.
1210 bool isExpectedPropIdImplemented = false;
1211 for (const auto& cfgPtr : result.value()) {
1212 const IHalPropConfig& cfg = *cfgPtr;
1213 if (expectedPropId == cfg.getPropId()) {
1214 isExpectedPropIdImplemented = true;
1215 break;
1216 }
1217 }
1218
1219 if (!isExpectedPropIdImplemented) {
1220 GTEST_SKIP() << StringPrintf("Property %" PRId32 " has not been implemented",
1221 expectedPropId);
1222 }
1223
1224 result = mVhalClient->getPropConfigs({expectedPropId});
1225 ASSERT_TRUE(result.ok()) << "Failed to get required property config, error: "
1226 << result.error().message();
1227
1228 ASSERT_EQ(result.value().size(), 1u)
1229 << StringPrintf("Expect to get exactly 1 config, got %zu", result.value().size());
1230
1231 const auto& config = result.value().at(0);
1232 int actualPropId = config->getPropId();
1233 int actualChangeMode = config->getChangeMode();
1234
1235 ASSERT_EQ(actualPropId, expectedPropId)
1236 << StringPrintf("Expect to get property ID: %i, got %i", expectedPropId, actualPropId);
1237
1238 int globalAccess = config->getAccess();
1239 if (config->getAreaConfigSize() == 0) {
1240 verifyAccessMode(globalAccess, param.accessModes);
1241 } else {
1242 for (const auto& areaConfig : config->getAreaConfigs()) {
1243 int areaConfigAccess = areaConfig->getAccess();
1244 int actualAccess = (areaConfigAccess != toInt(VehiclePropertyAccess::NONE))
1245 ? areaConfigAccess
1246 : globalAccess;
1247 verifyAccessMode(actualAccess, param.accessModes);
1248 }
1249 }
1250
1251 if (actualPropId != toInt(VehicleProperty::REMOVE_USER)) {
1252 EXPECT_EQ(actualChangeMode, expectedChangeMode)
1253 << StringPrintf("Expect to get VehiclePropertyChangeMode: %i, got %i",
1254 expectedChangeMode, actualChangeMode);
1255 } else {
1256 // Special logic for REMOVE_USER property. We allow both STATIC and ON_CHANGE change mode
1257 // because historically we define the change mode to be STATIC which is incorrect, it should
1258 // be on_change. For backward compatibility, we have to allow both.
1259 EXPECT_THAT(actualChangeMode, ::testing::AnyOf(toInt(VehiclePropertyChangeMode::STATIC),
1260 toInt(VehiclePropertyChangeMode::ON_CHANGE)))
1261 << StringPrintf(
1262 "Expect to get VehiclePropertyChangeMode as one of: "
1263 "[STATIC, ON_CHANGE], got %i",
1264 actualChangeMode);
1265 }
1266
1267 std::unordered_set<std::string> annotations;
1268 auto it = AnnotationsForVehicleProperty.find(param.propId);
1269 if (it != AnnotationsForVehicleProperty.end()) {
1270 annotations = it->second;
1271 }
1272
1273 VehiclePropertyType propertyType = getPropertyType(expectedPropId);
1274 verifyPropertyConfigMinMaxValue(config.get(), propertyType);
1275 if (annotations.find(ANNOTATION_REQUIRE_MIN_MAX_VALUE) != annotations.end()) {
1276 verifyPropertyConfigRequireMinMaxValue(config.get(), propertyType);
1277 }
1278 if (annotations.find(ANNOTATION_REQUIRE_SUPPORTED_VALUES) != annotations.end()) {
1279 verifyPropertyConfigRequireSupportedValues(config.get(), annotations);
1280 }
1281 if (annotations.find(ANNOTATIONS_DATA_ENUM) != annotations.end()) {
1282 verifyPropertyConfigDataEnum(config.get());
1283 }
1284 }
1285
getDescriptors()1286 std::vector<ServiceDescriptor> getDescriptors() {
1287 std::vector<ServiceDescriptor> descriptors;
1288 for (std::string name : getAidlHalInstanceNames(IVehicle::descriptor)) {
1289 descriptors.push_back({
1290 .name = name,
1291 .isAidlService = true,
1292 });
1293 }
1294 for (std::string name : getAllHalInstanceNames(
1295 android::hardware::automotive::vehicle::V2_0::IVehicle::descriptor)) {
1296 descriptors.push_back({
1297 .name = name,
1298 .isAidlService = false,
1299 });
1300 }
1301 return descriptors;
1302 }
1303
getPropertyConfigTestParams()1304 std::vector<PropertyConfigTestParam> getPropertyConfigTestParams() {
1305 std::vector<PropertyConfigTestParam> testParams;
1306 for (const auto& [propId, accessModes] : AllowedAccessForVehicleProperty) {
1307 PropertyConfigTestParam param;
1308 param.propId = propId;
1309 param.accessModes = accessModes;
1310 param.changeMode = ChangeModeForVehicleProperty[propId];
1311 testParams.push_back(param);
1312 }
1313 return testParams;
1314 }
1315
1316 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VtsHalAutomotiveVehicleTargetTest);
1317 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VtsHalAutomotivePropertyConfigTest);
1318
1319 INSTANTIATE_TEST_SUITE_P(PerInstance, VtsHalAutomotiveVehicleTargetTest,
1320 testing::ValuesIn(getDescriptors()),
__anon8ca97aa90202(const testing::TestParamInfo<ServiceDescriptor>& info) 1321 [](const testing::TestParamInfo<ServiceDescriptor>& info) {
1322 std::string name = "";
1323 if (info.param.isAidlService) {
1324 name += "aidl_";
1325 } else {
1326 name += "hidl_";
1327 }
1328 name += info.param.name;
1329 return Sanitize(name);
1330 });
1331
1332 INSTANTIATE_TEST_SUITE_P(PerInstance, VtsHalAutomotivePropertyConfigTest,
1333 testing::Combine(testing::ValuesIn(getPropertyConfigTestParams()),
1334 testing::ValuesIn(getDescriptors())),
1335 [](const testing::TestParamInfo<
__anon8ca97aa90302(const testing::TestParamInfo< std::tuple<PropertyConfigTestParam, ServiceDescriptor>>& info) 1336 std::tuple<PropertyConfigTestParam, ServiceDescriptor>>& info) {
1337 std::string name = "";
1338 if (std::get<1>(info.param).isAidlService) {
1339 name += "aidl_";
1340 } else {
1341 name += "hidl_";
1342 }
1343 name += std::get<1>(info.param).name;
1344 name += "_" + toString(std::get<0>(info.param).propId);
1345 return Sanitize(name);
1346 });
1347
main(int argc,char ** argv)1348 int main(int argc, char** argv) {
1349 ::testing::InitGoogleTest(&argc, argv);
1350 ABinderProcess_setThreadPoolMaxThreadCount(1);
1351 return RUN_ALL_TESTS();
1352 }
1353