1 /*
2 * Copyright (C) 2020 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 <android/hardware/automotive/vehicle/2.0/IVehicle.h>
20 #include <utils/Log.h>
21 #include <unordered_set>
22
23 #include <gtest/gtest.h>
24 #include <hidl/GtestPrinter.h>
25 #include <hidl/ServiceManagement.h>
26
27 using namespace android::hardware::automotive::vehicle::V2_0;
28 using ::android::sp;
29 using ::android::hardware::hidl_vec;
30 using ::android::hardware::Return;
31
32 constexpr auto kTimeout = std::chrono::milliseconds(500);
33 constexpr auto kInvalidProp = 0x31600207;
34
35 class VtsVehicleCallback : public IVehicleCallback {
36 private:
37 using MutexGuard = std::lock_guard<std::mutex>;
38 using HidlVecOfValues = hidl_vec<VehiclePropValue>;
39 std::mutex mLock;
40 std::condition_variable mEventCond;
41 std::vector<HidlVecOfValues> mReceivedEvents;
42
43 public:
onPropertyEvent(const hidl_vec<VehiclePropValue> & values)44 Return<void> onPropertyEvent(const hidl_vec<VehiclePropValue>& values) override {
45 {
46 MutexGuard guard(mLock);
47 mReceivedEvents.push_back(values);
48 }
49 mEventCond.notify_one();
50 return Return<void>();
51 }
52
onPropertySet(const VehiclePropValue &)53 Return<void> onPropertySet(const VehiclePropValue& /* value */) override {
54 return Return<void>();
55 }
onPropertySetError(StatusCode,int32_t,int32_t)56 Return<void> onPropertySetError(StatusCode /* errorCode */, int32_t /* propId */,
57 int32_t /* areaId */) override {
58 return Return<void>();
59 }
60
waitForExpectedEvents(size_t expectedEvents)61 bool waitForExpectedEvents(size_t expectedEvents) {
62 std::unique_lock<std::mutex> g(mLock);
63
64 if (expectedEvents == 0 && mReceivedEvents.size() == 0) {
65 return mEventCond.wait_for(g, kTimeout) == std::cv_status::timeout;
66 }
67
68 while (expectedEvents != mReceivedEvents.size()) {
69 if (mEventCond.wait_for(g, kTimeout) == std::cv_status::timeout) {
70 return false;
71 }
72 }
73 return true;
74 }
75
reset()76 void reset() { mReceivedEvents.clear(); }
77 };
78
79 class VehicleHalHidlTest : public testing::TestWithParam<std::string> {
80 public:
SetUp()81 virtual void SetUp() override {
82 mVehicle = IVehicle::getService(GetParam());
83 ASSERT_NE(mVehicle.get(), nullptr);
84 }
TearDown()85 virtual void TearDown() override {}
86
87 sp<IVehicle> mVehicle;
88
isBooleanGlobalProp(int32_t property)89 bool isBooleanGlobalProp(int32_t property) {
90 return (property & (int)VehiclePropertyType::MASK) == (int)VehiclePropertyType::BOOLEAN &&
91 (property & (int)VehicleArea::MASK) == (int)VehicleArea::GLOBAL;
92 }
93
invokeGet(int32_t property,int32_t areaId)94 void invokeGet(int32_t property, int32_t areaId) {
95 VehiclePropValue requestedValue{};
96 requestedValue.prop = property;
97 requestedValue.areaId = areaId;
98
99 invokeGet(requestedValue);
100 }
101
invokeGet(const VehiclePropValue & requestedPropValue)102 void invokeGet(const VehiclePropValue& requestedPropValue) {
103 mActualValue = VehiclePropValue{}; // reset previous values
104
105 StatusCode refStatus;
106 VehiclePropValue refValue;
107 bool isCalled = false;
108 mVehicle->get(requestedPropValue,
109 [&refStatus, &refValue, &isCalled](StatusCode status,
110 const VehiclePropValue& value) {
111 refStatus = status;
112 refValue = value;
113 isCalled = true;
114 });
115 ASSERT_TRUE(isCalled) << "callback wasn't called for property: " << requestedPropValue.prop;
116
117 mActualValue = refValue;
118 mActualStatusCode = refStatus;
119 }
120
121 VehiclePropValue mActualValue;
122 StatusCode mActualStatusCode;
123 };
124
125 // Test getAllPropConfig() returns at least 4 property configs.
TEST_P(VehicleHalHidlTest,getAllPropConfigs)126 TEST_P(VehicleHalHidlTest, getAllPropConfigs) {
127 ALOGD("VehicleHalHidlTest::getAllPropConfigs");
128 bool isCalled = false;
129 hidl_vec<VehiclePropConfig> propConfigs;
130 mVehicle->getAllPropConfigs([&isCalled, &propConfigs](const hidl_vec<VehiclePropConfig>& cfgs) {
131 propConfigs = cfgs;
132 isCalled = true;
133 });
134 ASSERT_TRUE(isCalled);
135 ASSERT_GE(propConfigs.size(), 4);
136 }
137
138 // Test getPropConfig() can query all properties listed in CDD.
TEST_P(VehicleHalHidlTest,getPropConfigs)139 TEST_P(VehicleHalHidlTest, getPropConfigs) {
140 ALOGD("VehicleHalHidlTest::getPropConfigs");
141 // Check the properties listed in CDD
142 hidl_vec<int32_t> properties = {
143 (int)VehicleProperty::GEAR_SELECTION, (int)VehicleProperty::NIGHT_MODE,
144 (int)VehicleProperty::PARKING_BRAKE_ON, (int)VehicleProperty::PERF_VEHICLE_SPEED};
145 bool isCalled = false;
146 mVehicle->getPropConfigs(
147 properties, [&isCalled](StatusCode status, const hidl_vec<VehiclePropConfig>& cfgs) {
148 ASSERT_EQ(StatusCode::OK, status);
149 ASSERT_EQ(4u, cfgs.size());
150 isCalled = true;
151 });
152 ASSERT_TRUE(isCalled);
153 }
154
155 // Test getPropConfig() with an invalid propertyId returns an error code.
TEST_P(VehicleHalHidlTest,getPropConfigsWithInvalidProp)156 TEST_P(VehicleHalHidlTest, getPropConfigsWithInvalidProp) {
157 ALOGD("VehicleHalHidlTest::getPropConfigsWithInvalidProp");
158 hidl_vec<int32_t> properties = {kInvalidProp};
159 bool isCalled = false;
160 mVehicle->getPropConfigs(
161 properties, [&isCalled](StatusCode status, const hidl_vec<VehiclePropConfig>& cfgs) {
162 ASSERT_NE(StatusCode::OK, status);
163 ASSERT_EQ(0, cfgs.size());
164 isCalled = true;
165 });
166 ASSERT_TRUE(isCalled);
167 }
168
169 // Test get() return current value for properties.
TEST_P(VehicleHalHidlTest,get)170 TEST_P(VehicleHalHidlTest, get) {
171 ALOGD("VehicleHalHidlTest::get");
172 invokeGet((int)VehicleProperty::PERF_VEHICLE_SPEED, 0);
173 ASSERT_EQ(StatusCode::OK, mActualStatusCode);
174 }
175
176 // Test get() with an invalid propertyId return an error codes.
TEST_P(VehicleHalHidlTest,getInvalidProp)177 TEST_P(VehicleHalHidlTest, getInvalidProp) {
178 ALOGD("VehicleHalHidlTest::getInvalidProp");
179
180 invokeGet(kInvalidProp, 0);
181 ASSERT_NE(StatusCode::OK, mActualStatusCode);
182 }
183
184 // Test set() on read_write properties.
TEST_P(VehicleHalHidlTest,setProp)185 TEST_P(VehicleHalHidlTest, setProp) {
186 ALOGD("VehicleHalHidlTest::setProp");
187 hidl_vec<VehiclePropConfig> propConfigs;
188 // skip hvac related properties
189 std::unordered_set<int32_t> hvacProps = {(int)VehicleProperty::HVAC_DEFROSTER,
190 (int)VehicleProperty::HVAC_AC_ON,
191 (int)VehicleProperty::HVAC_MAX_AC_ON,
192 (int)VehicleProperty::HVAC_MAX_DEFROST_ON,
193 (int)VehicleProperty::HVAC_RECIRC_ON,
194 (int)VehicleProperty::HVAC_DUAL_ON,
195 (int)VehicleProperty::HVAC_AUTO_ON,
196 (int)VehicleProperty::HVAC_POWER_ON,
197 (int)VehicleProperty::HVAC_AUTO_RECIRC_ON,
198 (int)VehicleProperty::HVAC_ELECTRIC_DEFROSTER_ON};
199 mVehicle->getAllPropConfigs(
200 [&propConfigs](const hidl_vec<VehiclePropConfig>& cfgs) { propConfigs = cfgs; });
201 for (const VehiclePropConfig& cfg : propConfigs) {
202 // test on boolean and writable property
203 if (cfg.access == VehiclePropertyAccess::READ_WRITE && isBooleanGlobalProp(cfg.prop) &&
204 !hvacProps.count(cfg.prop)) {
205 invokeGet(cfg.prop, 0);
206 int setValue = mActualValue.value.int32Values[0] == 1 ? 0 : 1;
207 VehiclePropValue propToSet = mActualValue;
208 propToSet.value.int32Values[0] = setValue;
209 ASSERT_EQ(StatusCode::OK, mVehicle->set(propToSet))
210 << "Invalid status code for setting property: " << cfg.prop;
211 // check set success
212 invokeGet(cfg.prop, 0);
213 ASSERT_EQ(StatusCode::OK, mActualStatusCode);
214 ASSERT_EQ(setValue, mActualValue.value.int32Values[0])
215 << "Failed to set value for property: " << cfg.prop;
216 }
217 }
218 }
219
220 // Test set() on an read_only property.
TEST_P(VehicleHalHidlTest,setNotWritableProp)221 TEST_P(VehicleHalHidlTest, setNotWritableProp) {
222 ALOGD("VehicleHalHidlTest::setNotWritableProp");
223 invokeGet(static_cast<int>(VehicleProperty::PERF_VEHICLE_SPEED), 0);
224 ASSERT_EQ(StatusCode::OK, mActualStatusCode);
225 VehiclePropValue vehicleSpeed = mActualValue;
226
227 ASSERT_EQ(StatusCode::ACCESS_DENIED, mVehicle->set(vehicleSpeed));
228 }
229
230 // Test subscribe() and unsubscribe().
TEST_P(VehicleHalHidlTest,subscribeAndUnsubscribe)231 TEST_P(VehicleHalHidlTest, subscribeAndUnsubscribe) {
232 ALOGD("VehicleHalHidlTest::subscribeAndUnsubscribe");
233 const auto prop = static_cast<int>(VehicleProperty::PERF_VEHICLE_SPEED);
234 sp<VtsVehicleCallback> cb = new VtsVehicleCallback();
235
236 hidl_vec<SubscribeOptions> options = {
237 SubscribeOptions{.propId = prop, 100.0, .flags = SubscribeFlags::EVENTS_FROM_CAR}};
238
239 ASSERT_EQ(StatusCode::OK, mVehicle->subscribe(cb, options));
240 ASSERT_TRUE(cb->waitForExpectedEvents(10));
241
242 ASSERT_EQ(StatusCode::OK, mVehicle->unsubscribe(cb, prop));
243 cb->reset();
244 ASSERT_FALSE(cb->waitForExpectedEvents(10));
245 }
246
247 // Test subscribe() with an invalid property.
TEST_P(VehicleHalHidlTest,subscribeInvalidProp)248 TEST_P(VehicleHalHidlTest, subscribeInvalidProp) {
249 ALOGD("VehicleHalHidlTest::subscribeInvalidProp");
250
251 sp<VtsVehicleCallback> cb = new VtsVehicleCallback();
252
253 hidl_vec<SubscribeOptions> options = {SubscribeOptions{
254 .propId = kInvalidProp, 10.0, .flags = SubscribeFlags::EVENTS_FROM_CAR}};
255
256 ASSERT_NE(StatusCode::OK, mVehicle->subscribe(cb, options));
257 }
258
259 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VehicleHalHidlTest);
260 INSTANTIATE_TEST_SUITE_P(
261 PerInstance, VehicleHalHidlTest,
262 testing::ValuesIn(android::hardware::getAllHalInstanceNames(IVehicle::descriptor)),
263 android::hardware::PrintInstanceNameToString);
264