1 /*
2 * Copyright (C) 2021 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 "DefaultVehicleHalServer"
18
19 #include <fstream>
20
21 #include <android-base/logging.h>
22 #include <utils/SystemClock.h>
23
24 #include "vhal_v2_0/DefaultConfig.h"
25 #include "vhal_v2_0/JsonFakeValueGenerator.h"
26 #include "vhal_v2_0/LinearFakeValueGenerator.h"
27
28 #include "DefaultVehicleHalServer.h"
29
30 namespace android {
31 namespace hardware {
32 namespace automotive {
33 namespace vehicle {
34 namespace V2_0 {
35
36 namespace impl {
37
storePropInitialValue(const ConfigDeclaration & config)38 void DefaultVehicleHalServer::storePropInitialValue(const ConfigDeclaration& config) {
39 VehiclePropConfig cfg = config.config;
40
41 // A global property will have only a single area
42 int32_t numAreas = isGlobalProp(cfg.prop) ? 1 : cfg.areaConfigs.size();
43
44 for (int i = 0; i < numAreas; i++) {
45 int32_t curArea = isGlobalProp(cfg.prop) ? 0 : cfg.areaConfigs[i].areaId;
46
47 // Create a separate instance for each individual zone
48 VehiclePropValue prop = {
49 .areaId = curArea,
50 .prop = cfg.prop,
51 };
52
53 if (config.initialAreaValues.empty()) {
54 prop.value = config.initialValue;
55 } else if (auto valueForAreaIt = config.initialAreaValues.find(curArea);
56 valueForAreaIt != config.initialAreaValues.end()) {
57 prop.value = valueForAreaIt->second;
58 } else {
59 LOG(WARNING) << __func__ << " failed to get default value for"
60 << " prop 0x" << std::hex << cfg.prop << " area 0x" << std::hex << curArea;
61 prop.status = VehiclePropertyStatus::UNAVAILABLE;
62 }
63
64 mServerSidePropStore.writeValue(prop, true);
65 }
66 }
67
DefaultVehicleHalServer()68 DefaultVehicleHalServer::DefaultVehicleHalServer() {
69 for (auto& it : kVehicleProperties) {
70 VehiclePropConfig cfg = it.config;
71 mServerSidePropStore.registerProperty(cfg);
72 storePropInitialValue(it);
73 }
74 }
75
sendAllValuesToClient()76 void DefaultVehicleHalServer::sendAllValuesToClient() {
77 constexpr bool update_status = true;
78 auto values = mServerSidePropStore.readAllValues();
79 for (const auto& value : values) {
80 onPropertyValueFromCar(value, update_status);
81 }
82 }
83
getGenerator()84 GeneratorHub* DefaultVehicleHalServer::getGenerator() {
85 return &mGeneratorHub;
86 }
87
getValuePool() const88 VehiclePropValuePool* DefaultVehicleHalServer::getValuePool() const {
89 if (!mValuePool) {
90 LOG(WARNING) << __func__ << ": Value pool not set!";
91 }
92 return mValuePool;
93 }
94
setValuePool(VehiclePropValuePool * valuePool)95 void DefaultVehicleHalServer::setValuePool(VehiclePropValuePool* valuePool) {
96 if (!valuePool) {
97 LOG(WARNING) << __func__ << ": Setting value pool to nullptr!";
98 }
99 mValuePool = valuePool;
100 }
101
onFakeValueGenerated(const VehiclePropValue & value)102 void DefaultVehicleHalServer::onFakeValueGenerated(const VehiclePropValue& value) {
103 constexpr bool updateStatus = true;
104 LOG(DEBUG) << __func__ << ": " << toString(value);
105 auto updatedPropValue = getValuePool()->obtain(value);
106 if (updatedPropValue) {
107 updatedPropValue->timestamp = value.timestamp;
108 updatedPropValue->status = VehiclePropertyStatus::AVAILABLE;
109 mServerSidePropStore.writeValue(*updatedPropValue, updateStatus);
110 onPropertyValueFromCar(*updatedPropValue, updateStatus);
111 }
112 }
113
onGetAllPropertyConfig() const114 std::vector<VehiclePropConfig> DefaultVehicleHalServer::onGetAllPropertyConfig() const {
115 return mServerSidePropStore.getAllConfigs();
116 }
117
handleGenerateFakeDataRequest(const VehiclePropValue & request)118 StatusCode DefaultVehicleHalServer::handleGenerateFakeDataRequest(const VehiclePropValue& request) {
119 constexpr bool updateStatus = true;
120
121 LOG(INFO) << __func__;
122 const auto& v = request.value;
123 if (!v.int32Values.size()) {
124 LOG(ERROR) << __func__ << ": expected at least \"command\" field in int32Values";
125 return StatusCode::INVALID_ARG;
126 }
127
128 FakeDataCommand command = static_cast<FakeDataCommand>(v.int32Values[0]);
129
130 switch (command) {
131 case FakeDataCommand::StartLinear: {
132 LOG(INFO) << __func__ << ", FakeDataCommand::StartLinear";
133 if (v.int32Values.size() < 2) {
134 LOG(ERROR) << __func__ << ": expected property ID in int32Values";
135 return StatusCode::INVALID_ARG;
136 }
137 if (!v.int64Values.size()) {
138 LOG(ERROR) << __func__ << ": interval is not provided in int64Values";
139 return StatusCode::INVALID_ARG;
140 }
141 if (v.floatValues.size() < 3) {
142 LOG(ERROR) << __func__ << ": expected at least 3 elements in floatValues, got: "
143 << v.floatValues.size();
144 return StatusCode::INVALID_ARG;
145 }
146 int32_t cookie = v.int32Values[1];
147 getGenerator()->registerGenerator(cookie,
148 std::make_unique<LinearFakeValueGenerator>(request));
149 break;
150 }
151 case FakeDataCommand::StartJson: {
152 LOG(INFO) << __func__ << ", FakeDataCommand::StartJson";
153 if (v.stringValue.empty()) {
154 LOG(ERROR) << __func__ << ": path to JSON file is missing";
155 return StatusCode::INVALID_ARG;
156 }
157 int32_t cookie = std::hash<std::string>()(v.stringValue);
158 getGenerator()->registerGenerator(cookie,
159 std::make_unique<JsonFakeValueGenerator>(request));
160 break;
161 }
162 case FakeDataCommand::StopLinear: {
163 LOG(INFO) << __func__ << ", FakeDataCommand::StopLinear";
164 if (v.int32Values.size() < 2) {
165 LOG(ERROR) << __func__ << ": expected property ID in int32Values";
166 return StatusCode::INVALID_ARG;
167 }
168 int32_t cookie = v.int32Values[1];
169 getGenerator()->unregisterGenerator(cookie);
170 break;
171 }
172 case FakeDataCommand::StopJson: {
173 LOG(INFO) << __func__ << ", FakeDataCommand::StopJson";
174 if (v.stringValue.empty()) {
175 LOG(ERROR) << __func__ << ": path to JSON file is missing";
176 return StatusCode::INVALID_ARG;
177 }
178 int32_t cookie = std::hash<std::string>()(v.stringValue);
179 getGenerator()->unregisterGenerator(cookie);
180 break;
181 }
182 case FakeDataCommand::KeyPress: {
183 LOG(INFO) << __func__ << ", FakeDataCommand::KeyPress";
184 int32_t keyCode = request.value.int32Values[2];
185 int32_t display = request.value.int32Values[3];
186 // Send back to HAL
187 onPropertyValueFromCar(
188 *createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_DOWN, keyCode, display),
189 updateStatus);
190 onPropertyValueFromCar(
191 *createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_UP, keyCode, display),
192 updateStatus);
193 break;
194 }
195 default: {
196 LOG(ERROR) << __func__ << ": unexpected command: " << toInt(command);
197 return StatusCode::INVALID_ARG;
198 }
199 }
200 return StatusCode::OK;
201 }
202
createApPowerStateReq(VehicleApPowerStateReq state,int32_t param)203 DefaultVehicleHalServer::VehiclePropValuePtr DefaultVehicleHalServer::createApPowerStateReq(
204 VehicleApPowerStateReq state, int32_t param) {
205 auto req = getValuePool()->obtain(VehiclePropertyType::INT32_VEC, 2);
206 req->prop = toInt(VehicleProperty::AP_POWER_STATE_REQ);
207 req->areaId = 0;
208 req->timestamp = elapsedRealtimeNano();
209 req->status = VehiclePropertyStatus::AVAILABLE;
210 req->value.int32Values[0] = toInt(state);
211 req->value.int32Values[1] = param;
212 return req;
213 }
214
createHwInputKeyProp(VehicleHwKeyInputAction action,int32_t keyCode,int32_t targetDisplay)215 DefaultVehicleHalServer::VehiclePropValuePtr DefaultVehicleHalServer::createHwInputKeyProp(
216 VehicleHwKeyInputAction action, int32_t keyCode, int32_t targetDisplay) {
217 auto keyEvent = getValuePool()->obtain(VehiclePropertyType::INT32_VEC, 3);
218 keyEvent->prop = toInt(VehicleProperty::HW_KEY_INPUT);
219 keyEvent->areaId = 0;
220 keyEvent->timestamp = elapsedRealtimeNano();
221 keyEvent->status = VehiclePropertyStatus::AVAILABLE;
222 keyEvent->value.int32Values[0] = toInt(action);
223 keyEvent->value.int32Values[1] = keyCode;
224 keyEvent->value.int32Values[2] = targetDisplay;
225 return keyEvent;
226 }
227
onSetProperty(const VehiclePropValue & value,bool updateStatus)228 StatusCode DefaultVehicleHalServer::onSetProperty(const VehiclePropValue& value,
229 bool updateStatus) {
230 LOG(DEBUG) << "onSetProperty(" << value.prop << ")";
231
232 // Some properties need to be treated non-trivially
233 switch (value.prop) {
234 case kGenerateFakeDataControllingProperty:
235 return handleGenerateFakeDataRequest(value);
236
237 // set the value from vehicle side, used in end to end test.
238 case kSetIntPropertyFromVehicleForTest: {
239 auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::INT32, 1);
240 updatedPropValue->prop = value.value.int32Values[0];
241 updatedPropValue->value.int32Values[0] = value.value.int32Values[1];
242 updatedPropValue->timestamp = value.value.int64Values[0];
243 updatedPropValue->areaId = value.areaId;
244 onPropertyValueFromCar(*updatedPropValue, updateStatus);
245 return StatusCode::OK;
246 }
247 case kSetFloatPropertyFromVehicleForTest: {
248 auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::FLOAT, 1);
249 updatedPropValue->prop = value.value.int32Values[0];
250 updatedPropValue->value.floatValues[0] = value.value.floatValues[0];
251 updatedPropValue->timestamp = value.value.int64Values[0];
252 updatedPropValue->areaId = value.areaId;
253 onPropertyValueFromCar(*updatedPropValue, updateStatus);
254 return StatusCode::OK;
255 }
256 case kSetBooleanPropertyFromVehicleForTest: {
257 auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::BOOLEAN, 1);
258 updatedPropValue->prop = value.value.int32Values[1];
259 updatedPropValue->value.int32Values[0] = value.value.int32Values[0];
260 updatedPropValue->timestamp = value.value.int64Values[0];
261 updatedPropValue->areaId = value.areaId;
262 onPropertyValueFromCar(*updatedPropValue, updateStatus);
263 return StatusCode::OK;
264 }
265
266 case AP_POWER_STATE_REPORT:
267 switch (value.value.int32Values[0]) {
268 case toInt(VehicleApPowerStateReport::DEEP_SLEEP_EXIT):
269 case toInt(VehicleApPowerStateReport::SHUTDOWN_CANCELLED):
270 case toInt(VehicleApPowerStateReport::WAIT_FOR_VHAL):
271 // CPMS is in WAIT_FOR_VHAL state, simply move to ON
272 // Send back to HAL
273 // ALWAYS update status for generated property value
274 onPropertyValueFromCar(*createApPowerStateReq(VehicleApPowerStateReq::ON, 0),
275 true /* updateStatus */);
276 break;
277 case toInt(VehicleApPowerStateReport::DEEP_SLEEP_ENTRY):
278 case toInt(VehicleApPowerStateReport::SHUTDOWN_START):
279 // CPMS is in WAIT_FOR_FINISH state, send the FINISHED command
280 // Send back to HAL
281 // ALWAYS update status for generated property value
282 onPropertyValueFromCar(
283 *createApPowerStateReq(VehicleApPowerStateReq::FINISHED, 0),
284 true /* updateStatus */);
285 break;
286 case toInt(VehicleApPowerStateReport::ON):
287 case toInt(VehicleApPowerStateReport::SHUTDOWN_POSTPONE):
288 case toInt(VehicleApPowerStateReport::SHUTDOWN_PREPARE):
289 // Do nothing
290 break;
291 default:
292 // Unknown state
293 break;
294 }
295 break;
296
297 #ifdef ENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING
298 case toInt(VehicleProperty::CLUSTER_REPORT_STATE):
299 case toInt(VehicleProperty::CLUSTER_REQUEST_DISPLAY):
300 case toInt(VehicleProperty::CLUSTER_NAVIGATION_STATE):
301 case VENDOR_CLUSTER_SWITCH_UI:
302 case VENDOR_CLUSTER_DISPLAY_STATE: {
303 auto updatedPropValue = createVehiclePropValue(getPropType(value.prop), 0);
304 updatedPropValue->prop = value.prop & ~toInt(VehiclePropertyGroup::MASK);
305 if (isSystemProperty(value.prop)) {
306 updatedPropValue->prop |= toInt(VehiclePropertyGroup::VENDOR);
307 } else {
308 updatedPropValue->prop |= toInt(VehiclePropertyGroup::SYSTEM);
309 }
310 updatedPropValue->value = value.value;
311 updatedPropValue->timestamp = elapsedRealtimeNano();
312 updatedPropValue->areaId = value.areaId;
313 onPropertyValueFromCar(*updatedPropValue, updateStatus);
314 return StatusCode::OK;
315 }
316 #endif // ENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING
317
318 default:
319 break;
320 }
321
322 // In the real vhal, the value will be sent to Car ECU.
323 // We just pretend it is done here and send back to HAL
324 auto updatedPropValue = getValuePool()->obtain(value);
325 updatedPropValue->timestamp = elapsedRealtimeNano();
326
327 mServerSidePropStore.writeValue(*updatedPropValue, updateStatus);
328 onPropertyValueFromCar(*updatedPropValue, updateStatus);
329 return StatusCode::OK;
330 }
331
332 } // namespace impl
333
334 } // namespace V2_0
335 } // namespace vehicle
336 } // namespace automotive
337 } // namespace hardware
338 } // namespace android
339