1 /*
2  * Copyright (C) 2017 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 #define LOG_TAG "VehicleEmulator_v2_0"
17 #include <android/log.h>
18 
19 #include <android-base/properties.h>
20 #include <log/log.h>
21 #include <utils/SystemClock.h>
22 #include <algorithm>
23 
24 #include <vhal_v2_0/VehicleUtils.h>
25 
26 #include "PipeComm.h"
27 #include "ProtoMessageConverter.h"
28 #include "SocketComm.h"
29 
30 #include "VehicleEmulator.h"
31 
32 namespace android {
33 namespace hardware {
34 namespace automotive {
35 namespace vehicle {
36 namespace V2_0 {
37 
38 namespace impl {
39 
VehicleEmulator(EmulatedVehicleHalIface * hal)40 VehicleEmulator::VehicleEmulator(EmulatedVehicleHalIface* hal) : mHal{hal} {
41     mHal->registerEmulator(this);
42 
43     ALOGI("Starting SocketComm");
44     mSocketComm = std::make_unique<SocketComm>(this);
45     mSocketComm->start();
46 
47     if (isInEmulator()) {
48         ALOGI("Starting PipeComm");
49         mPipeComm = std::make_unique<PipeComm>(this);
50         mPipeComm->start();
51     }
52 }
53 
~VehicleEmulator()54 VehicleEmulator::~VehicleEmulator() {
55     mSocketComm->stop();
56     if (mPipeComm) {
57         mPipeComm->stop();
58     }
59 }
60 
61 /**
62  * This is called by the HAL when a property changes. We need to notify our clients that it has
63  * changed.
64  */
doSetValueFromClient(const VehiclePropValue & propValue)65 void VehicleEmulator::doSetValueFromClient(const VehiclePropValue& propValue) {
66     vhal_proto::EmulatorMessage msg;
67     vhal_proto::VehiclePropValue* val = msg.add_value();
68     populateProtoVehiclePropValue(val, &propValue);
69     msg.set_status(vhal_proto::RESULT_OK);
70     msg.set_msg_type(vhal_proto::SET_PROPERTY_ASYNC);
71 
72     mSocketComm->sendMessage(msg);
73     if (mPipeComm) {
74         mPipeComm->sendMessage(msg);
75     }
76 }
77 
doGetConfig(VehicleEmulator::EmulatorMessage const & rxMsg,VehicleEmulator::EmulatorMessage & respMsg)78 void VehicleEmulator::doGetConfig(VehicleEmulator::EmulatorMessage const& rxMsg,
79                                   VehicleEmulator::EmulatorMessage& respMsg) {
80     std::vector<VehiclePropConfig> configs = mHal->listProperties();
81     vhal_proto::VehiclePropGet getProp = rxMsg.prop(0);
82 
83     respMsg.set_msg_type(vhal_proto::GET_CONFIG_RESP);
84     respMsg.set_status(vhal_proto::ERROR_INVALID_PROPERTY);
85 
86     for (auto& config : configs) {
87         // Find the config we are looking for
88         if (config.prop == getProp.prop()) {
89             vhal_proto::VehiclePropConfig* protoCfg = respMsg.add_config();
90             populateProtoVehicleConfig(protoCfg, config);
91             respMsg.set_status(vhal_proto::RESULT_OK);
92             break;
93         }
94     }
95 }
96 
doGetConfigAll(VehicleEmulator::EmulatorMessage const &,VehicleEmulator::EmulatorMessage & respMsg)97 void VehicleEmulator::doGetConfigAll(VehicleEmulator::EmulatorMessage const& /* rxMsg */,
98                                      VehicleEmulator::EmulatorMessage& respMsg) {
99     std::vector<VehiclePropConfig> configs = mHal->listProperties();
100 
101     respMsg.set_msg_type(vhal_proto::GET_CONFIG_ALL_RESP);
102     respMsg.set_status(vhal_proto::RESULT_OK);
103 
104     for (auto& config : configs) {
105         vhal_proto::VehiclePropConfig* protoCfg = respMsg.add_config();
106         populateProtoVehicleConfig(protoCfg, config);
107     }
108 }
109 
doGetProperty(VehicleEmulator::EmulatorMessage const & rxMsg,VehicleEmulator::EmulatorMessage & respMsg)110 void VehicleEmulator::doGetProperty(VehicleEmulator::EmulatorMessage const& rxMsg,
111                                     VehicleEmulator::EmulatorMessage& respMsg) {
112     int32_t areaId = 0;
113     vhal_proto::VehiclePropGet getProp = rxMsg.prop(0);
114     int32_t propId = getProp.prop();
115     vhal_proto::Status status = vhal_proto::ERROR_INVALID_PROPERTY;
116 
117     respMsg.set_msg_type(vhal_proto::GET_PROPERTY_RESP);
118 
119     if (getProp.has_area_id()) {
120         areaId = getProp.area_id();
121     }
122 
123     {
124         VehiclePropValue request = {
125                 .areaId = areaId,
126                 .prop = propId,
127         };
128         StatusCode halStatus;
129         auto val = mHal->get(request, &halStatus);
130         if (val != nullptr) {
131             vhal_proto::VehiclePropValue* protoVal = respMsg.add_value();
132             populateProtoVehiclePropValue(protoVal, val.get());
133             status = vhal_proto::RESULT_OK;
134         }
135     }
136 
137     respMsg.set_status(status);
138 }
139 
doGetPropertyAll(VehicleEmulator::EmulatorMessage const &,VehicleEmulator::EmulatorMessage & respMsg)140 void VehicleEmulator::doGetPropertyAll(VehicleEmulator::EmulatorMessage const& /* rxMsg */,
141                                        VehicleEmulator::EmulatorMessage& respMsg) {
142     respMsg.set_msg_type(vhal_proto::GET_PROPERTY_ALL_RESP);
143     respMsg.set_status(vhal_proto::RESULT_OK);
144 
145     {
146         for (const auto& prop : mHal->getAllProperties()) {
147             vhal_proto::VehiclePropValue* protoVal = respMsg.add_value();
148             populateProtoVehiclePropValue(protoVal, &prop);
149         }
150     }
151 }
152 
doSetProperty(VehicleEmulator::EmulatorMessage const & rxMsg,VehicleEmulator::EmulatorMessage & respMsg)153 void VehicleEmulator::doSetProperty(VehicleEmulator::EmulatorMessage const& rxMsg,
154                                     VehicleEmulator::EmulatorMessage& respMsg) {
155     vhal_proto::VehiclePropValue protoVal = rxMsg.value(0);
156     VehiclePropValue val = {
157             .timestamp = elapsedRealtimeNano(),
158             .areaId = protoVal.area_id(),
159             .prop = protoVal.prop(),
160             .status = (VehiclePropertyStatus)protoVal.status(),
161     };
162 
163     respMsg.set_msg_type(vhal_proto::SET_PROPERTY_RESP);
164 
165     // Copy value data if it is set.  This automatically handles complex data types if needed.
166     if (protoVal.has_string_value()) {
167         val.value.stringValue = protoVal.string_value().c_str();
168     }
169 
170     if (protoVal.has_bytes_value()) {
171         val.value.bytes = std::vector<uint8_t> { protoVal.bytes_value().begin(),
172                                                  protoVal.bytes_value().end() };
173     }
174 
175     if (protoVal.int32_values_size() > 0) {
176         val.value.int32Values = std::vector<int32_t> { protoVal.int32_values().begin(),
177                                                        protoVal.int32_values().end() };
178     }
179 
180     if (protoVal.int64_values_size() > 0) {
181         val.value.int64Values = std::vector<int64_t> { protoVal.int64_values().begin(),
182                                                        protoVal.int64_values().end() };
183     }
184 
185     if (protoVal.float_values_size() > 0) {
186         val.value.floatValues = std::vector<float> { protoVal.float_values().begin(),
187                                                      protoVal.float_values().end() };
188     }
189 
190     bool halRes = mHal->setPropertyFromVehicle(val);
191     respMsg.set_status(halRes ? vhal_proto::RESULT_OK : vhal_proto::ERROR_INVALID_PROPERTY);
192 }
193 
processMessage(vhal_proto::EmulatorMessage const & rxMsg,vhal_proto::EmulatorMessage & respMsg)194 void VehicleEmulator::processMessage(vhal_proto::EmulatorMessage const& rxMsg,
195                                      vhal_proto::EmulatorMessage& respMsg) {
196     switch (rxMsg.msg_type()) {
197         case vhal_proto::GET_CONFIG_CMD:
198             doGetConfig(rxMsg, respMsg);
199             break;
200         case vhal_proto::GET_CONFIG_ALL_CMD:
201             doGetConfigAll(rxMsg, respMsg);
202             break;
203         case vhal_proto::GET_PROPERTY_CMD:
204             doGetProperty(rxMsg, respMsg);
205             break;
206         case vhal_proto::GET_PROPERTY_ALL_CMD:
207             doGetPropertyAll(rxMsg, respMsg);
208             break;
209         case vhal_proto::SET_PROPERTY_CMD:
210             doSetProperty(rxMsg, respMsg);
211             break;
212         default:
213             ALOGW("%s: Unknown message received, type = %d", __func__, rxMsg.msg_type());
214             respMsg.set_status(vhal_proto::ERROR_UNIMPLEMENTED_CMD);
215             break;
216     }
217 }
218 
populateProtoVehicleConfig(vhal_proto::VehiclePropConfig * protoCfg,const VehiclePropConfig & cfg)219 void VehicleEmulator::populateProtoVehicleConfig(vhal_proto::VehiclePropConfig* protoCfg,
220                                                  const VehiclePropConfig& cfg) {
221     return proto_msg_converter::toProto(protoCfg, cfg);
222 }
223 
populateProtoVehiclePropValue(vhal_proto::VehiclePropValue * protoVal,const VehiclePropValue * val)224 void VehicleEmulator::populateProtoVehiclePropValue(vhal_proto::VehiclePropValue* protoVal,
225                                                     const VehiclePropValue* val) {
226     return proto_msg_converter::toProto(protoVal, *val);
227 }
228 
isInEmulator()229 bool isInEmulator() {
230     return android::base::GetBoolProperty("ro.boot.qemu", false);
231 }
232 
233 }  // impl
234 
235 }  // namespace V2_0
236 }  // namespace vehicle
237 }  // namespace automotive
238 }  // namespace hardware
239 }  // namespace android
240