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