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