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 #include "MockVehicleHardware.h"
18 #include "MockVehicleCallback.h"
19
20 #include <utils/Log.h>
21
22 namespace android {
23 namespace hardware {
24 namespace automotive {
25 namespace vehicle {
26
27 using ::aidl::android::hardware::automotive::vehicle::GetValueRequest;
28 using ::aidl::android::hardware::automotive::vehicle::GetValueResult;
29 using ::aidl::android::hardware::automotive::vehicle::SetValueRequest;
30 using ::aidl::android::hardware::automotive::vehicle::SetValueResult;
31 using ::aidl::android::hardware::automotive::vehicle::StatusCode;
32 using ::aidl::android::hardware::automotive::vehicle::SubscribeOptions;
33 using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
34 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
35
MockVehicleHardware()36 MockVehicleHardware::MockVehicleHardware() {
37 mRecurrentTimer = std::make_unique<RecurrentTimer>();
38 }
39
~MockVehicleHardware()40 MockVehicleHardware::~MockVehicleHardware() {
41 std::unique_lock<std::mutex> lk(mLock);
42 mCv.wait(lk, [this] { return mThreadCount == 0; });
43 mRecurrentTimer.reset();
44 }
45
getAllPropertyConfigs() const46 std::vector<VehiclePropConfig> MockVehicleHardware::getAllPropertyConfigs() const {
47 std::scoped_lock<std::mutex> lockGuard(mLock);
48 return mPropertyConfigs;
49 }
50
setValues(std::shared_ptr<const SetValuesCallback> callback,const std::vector<SetValueRequest> & requests)51 StatusCode MockVehicleHardware::setValues(std::shared_ptr<const SetValuesCallback> callback,
52 const std::vector<SetValueRequest>& requests) {
53 std::scoped_lock<std::mutex> lockGuard(mLock);
54 if (StatusCode status = handleRequestsLocked(__func__, callback, requests, &mSetValueRequests,
55 &mSetValueResponses);
56 status != StatusCode::OK) {
57 return status;
58 }
59 if (mPropertyChangeCallback == nullptr) {
60 return StatusCode::OK;
61 }
62 std::vector<VehiclePropValue> values;
63 for (auto& request : requests) {
64 values.push_back(request.value);
65 }
66 (*mPropertyChangeCallback)(values);
67 return StatusCode::OK;
68 }
69
getValues(std::shared_ptr<const GetValuesCallback> callback,const std::vector<GetValueRequest> & requests) const70 StatusCode MockVehicleHardware::getValues(std::shared_ptr<const GetValuesCallback> callback,
71 const std::vector<GetValueRequest>& requests) const {
72 std::scoped_lock<std::mutex> lockGuard(mLock);
73 if (mGetValueResponder != nullptr) {
74 return mGetValueResponder(callback, requests);
75 }
76 return handleRequestsLocked(__func__, callback, requests, &mGetValueRequests,
77 &mGetValueResponses);
78 }
79
setDumpResult(DumpResult result)80 void MockVehicleHardware::setDumpResult(DumpResult result) {
81 mDumpResult = result;
82 }
83
dump(const std::vector<std::string> &)84 DumpResult MockVehicleHardware::dump(const std::vector<std::string>&) {
85 return mDumpResult;
86 }
87
checkHealth()88 StatusCode MockVehicleHardware::checkHealth() {
89 return StatusCode::OK;
90 }
91
subscribe(SubscribeOptions options)92 StatusCode MockVehicleHardware::subscribe(SubscribeOptions options) {
93 {
94 std::scoped_lock<std::mutex> lockGuard(mLock);
95 mSubscribeOptions.push_back(options);
96 }
97 for (int32_t areaId : options.areaIds) {
98 if (auto status = subscribePropIdAreaId(options.propId, areaId, options.sampleRate);
99 status != StatusCode::OK) {
100 return status;
101 }
102 }
103 return StatusCode::OK;
104 }
105
getSubscribeOptions()106 std::vector<SubscribeOptions> MockVehicleHardware::getSubscribeOptions() {
107 std::scoped_lock<std::mutex> lockGuard(mLock);
108 return mSubscribeOptions;
109 }
110
clearSubscribeOptions()111 void MockVehicleHardware::clearSubscribeOptions() {
112 std::scoped_lock<std::mutex> lockGuard(mLock);
113 mSubscribeOptions.clear();
114 }
115
subscribePropIdAreaId(int32_t propId,int32_t areaId,float sampleRateHz)116 StatusCode MockVehicleHardware::subscribePropIdAreaId(int32_t propId, int32_t areaId,
117 float sampleRateHz) {
118 if (sampleRateHz == 0) {
119 // on-change property.
120 std::scoped_lock<std::mutex> lockGuard(mLock);
121 mSubOnChangePropIdAreaIds.insert(std::pair<int32_t, int32_t>(propId, areaId));
122 return StatusCode::OK;
123 }
124
125 // continuous property.
126 std::shared_ptr<std::function<void()>> action;
127
128 {
129 std::scoped_lock<std::mutex> lockGuard(mLock);
130 if (mRecurrentActions[propId][areaId] != nullptr) {
131 // Remove the previous action register for this [propId, areaId].
132 mRecurrentTimer->unregisterTimerCallback(mRecurrentActions[propId][areaId]);
133 }
134
135 // We are sure 'propertyChangeCallback' would be alive because we would unregister timer
136 // before destroying 'this' which owns mPropertyChangeCallback.
137 const PropertyChangeCallback* propertyChangeCallback = mPropertyChangeCallback.get();
138 action = std::make_shared<std::function<void()>>([propertyChangeCallback, propId, areaId] {
139 std::vector<VehiclePropValue> values = {
140 {
141 .areaId = areaId,
142 .prop = propId,
143 },
144 };
145 (*propertyChangeCallback)(values);
146 });
147 // Store the action in a map so that we could remove the action later.
148 mRecurrentActions[propId][areaId] = action;
149 }
150
151 // In mock implementation, we generate a new property change event for this property at sample
152 // rate.
153 int64_t interval = static_cast<int64_t>(1'000'000'000. / sampleRateHz);
154 mRecurrentTimer->registerTimerCallback(interval, action);
155 return StatusCode::OK;
156 }
157
unsubscribe(int32_t propId,int32_t areaId)158 StatusCode MockVehicleHardware::unsubscribe(int32_t propId, int32_t areaId) {
159 std::scoped_lock<std::mutex> lockGuard(mLock);
160 // For on-change property.
161 mSubOnChangePropIdAreaIds.erase(std::make_pair(propId, areaId));
162 // for continuous property.
163 if (mRecurrentActions[propId][areaId] != nullptr) {
164 // Remove the previous action register for this [propId, areaId].
165 mRecurrentTimer->unregisterTimerCallback(mRecurrentActions[propId][areaId]);
166 mRecurrentActions[propId].erase(areaId);
167 if (mRecurrentActions[propId].empty()) {
168 mRecurrentActions.erase(propId);
169 }
170 }
171 return StatusCode::OK;
172 }
173
getSubscribedOnChangePropIdAreaIds()174 std::set<std::pair<int32_t, int32_t>> MockVehicleHardware::getSubscribedOnChangePropIdAreaIds() {
175 std::scoped_lock<std::mutex> lockGuard(mLock);
176 std::set<std::pair<int32_t, int32_t>> propIdAreaIds;
177 propIdAreaIds = mSubOnChangePropIdAreaIds;
178 return propIdAreaIds;
179 }
180
getSubscribedContinuousPropIdAreaIds()181 std::set<std::pair<int32_t, int32_t>> MockVehicleHardware::getSubscribedContinuousPropIdAreaIds() {
182 std::scoped_lock<std::mutex> lockGuard(mLock);
183 std::set<std::pair<int32_t, int32_t>> propIdAreaIds;
184 for (const auto& [propId, actionByAreaId] : mRecurrentActions) {
185 for (const auto& [areaId, _] : actionByAreaId) {
186 propIdAreaIds.insert(std::make_pair(propId, areaId));
187 }
188 }
189 return propIdAreaIds;
190 }
191
registerOnPropertyChangeEvent(std::unique_ptr<const PropertyChangeCallback> callback)192 void MockVehicleHardware::registerOnPropertyChangeEvent(
193 std::unique_ptr<const PropertyChangeCallback> callback) {
194 std::scoped_lock<std::mutex> lockGuard(mLock);
195 mPropertyChangeCallback = std::move(callback);
196 }
197
registerOnPropertySetErrorEvent(std::unique_ptr<const PropertySetErrorCallback> callback)198 void MockVehicleHardware::registerOnPropertySetErrorEvent(
199 std::unique_ptr<const PropertySetErrorCallback> callback) {
200 std::scoped_lock<std::mutex> lockGuard(mLock);
201 mPropertySetErrorCallback = std::move(callback);
202 }
203
setPropertyConfigs(const std::vector<VehiclePropConfig> & configs)204 void MockVehicleHardware::setPropertyConfigs(const std::vector<VehiclePropConfig>& configs) {
205 std::scoped_lock<std::mutex> lockGuard(mLock);
206 mPropertyConfigs = configs;
207 }
208
addGetValueResponses(const std::vector<GetValueResult> & responses)209 void MockVehicleHardware::addGetValueResponses(const std::vector<GetValueResult>& responses) {
210 std::scoped_lock<std::mutex> lockGuard(mLock);
211 mGetValueResponses.push_back(responses);
212 }
213
addSetValueResponses(const std::vector<SetValueResult> & responses)214 void MockVehicleHardware::addSetValueResponses(const std::vector<SetValueResult>& responses) {
215 std::scoped_lock<std::mutex> lockGuard(mLock);
216 mSetValueResponses.push_back(responses);
217 }
218
setGetValueResponder(std::function<StatusCode (std::shared_ptr<const GetValuesCallback>,const std::vector<GetValueRequest> &)> && responder)219 void MockVehicleHardware::setGetValueResponder(
220 std::function<StatusCode(std::shared_ptr<const GetValuesCallback>,
221 const std::vector<GetValueRequest>&)>&& responder) {
222 std::scoped_lock<std::mutex> lockGuard(mLock);
223 mGetValueResponder = responder;
224 }
225
nextGetValueRequests()226 std::vector<GetValueRequest> MockVehicleHardware::nextGetValueRequests() {
227 std::scoped_lock<std::mutex> lockGuard(mLock);
228 std::optional<std::vector<GetValueRequest>> request = pop(mGetValueRequests);
229 if (!request.has_value()) {
230 return std::vector<GetValueRequest>();
231 }
232 return std::move(request.value());
233 }
234
nextSetValueRequests()235 std::vector<SetValueRequest> MockVehicleHardware::nextSetValueRequests() {
236 std::scoped_lock<std::mutex> lockGuard(mLock);
237 std::optional<std::vector<SetValueRequest>> request = pop(mSetValueRequests);
238 if (!request.has_value()) {
239 return std::vector<SetValueRequest>();
240 }
241 return std::move(request.value());
242 }
243
setStatus(const char * functionName,StatusCode status)244 void MockVehicleHardware::setStatus(const char* functionName, StatusCode status) {
245 std::scoped_lock<std::mutex> lockGuard(mLock);
246 mStatusByFunctions[functionName] = status;
247 }
248
setSleepTime(int64_t timeInNano)249 void MockVehicleHardware::setSleepTime(int64_t timeInNano) {
250 std::scoped_lock<std::mutex> lockGuard(mLock);
251 mSleepTime = timeInNano;
252 }
253
setPropertyOnChangeEventBatchingWindow(std::chrono::nanoseconds window)254 void MockVehicleHardware::setPropertyOnChangeEventBatchingWindow(std::chrono::nanoseconds window) {
255 std::scoped_lock<std::mutex> lockGuard(mLock);
256 mEventBatchingWindow = window;
257 }
258
getPropertyOnChangeEventBatchingWindow()259 std::chrono::nanoseconds MockVehicleHardware::getPropertyOnChangeEventBatchingWindow() {
260 std::scoped_lock<std::mutex> lockGuard(mLock);
261 return mEventBatchingWindow;
262 }
263
264 template <class ResultType>
returnResponse(std::shared_ptr<const std::function<void (std::vector<ResultType>)>> callback,std::list<std::vector<ResultType>> * storedResponses) const265 StatusCode MockVehicleHardware::returnResponse(
266 std::shared_ptr<const std::function<void(std::vector<ResultType>)>> callback,
267 std::list<std::vector<ResultType>>* storedResponses) const {
268 if (storedResponses->size() > 0) {
269 (*callback)(std::move(storedResponses->front()));
270 storedResponses->pop_front();
271 return StatusCode::OK;
272 } else {
273 ALOGE("no more response");
274 return StatusCode::INTERNAL_ERROR;
275 }
276 }
277
278 template StatusCode MockVehicleHardware::returnResponse<GetValueResult>(
279 std::shared_ptr<const std::function<void(std::vector<GetValueResult>)>> callback,
280 std::list<std::vector<GetValueResult>>* storedResponses) const;
281
282 template StatusCode MockVehicleHardware::returnResponse<SetValueResult>(
283 std::shared_ptr<const std::function<void(std::vector<SetValueResult>)>> callback,
284 std::list<std::vector<SetValueResult>>* storedResponses) const;
285
286 template <class RequestType, class ResultType>
handleRequestsLocked(const char * functionName,std::shared_ptr<const std::function<void (std::vector<ResultType>)>> callback,const std::vector<RequestType> & requests,std::list<std::vector<RequestType>> * storedRequests,std::list<std::vector<ResultType>> * storedResponses) const287 StatusCode MockVehicleHardware::handleRequestsLocked(
288 const char* functionName,
289 std::shared_ptr<const std::function<void(std::vector<ResultType>)>> callback,
290 const std::vector<RequestType>& requests,
291 std::list<std::vector<RequestType>>* storedRequests,
292 std::list<std::vector<ResultType>>* storedResponses) const {
293 storedRequests->push_back(requests);
294 if (auto it = mStatusByFunctions.find(functionName); it != mStatusByFunctions.end()) {
295 if (StatusCode status = it->second; status != StatusCode::OK) {
296 return status;
297 }
298 }
299
300 if (mSleepTime != 0) {
301 int64_t sleepTime = mSleepTime;
302 mThreadCount++;
303 std::thread t([this, callback, sleepTime, storedResponses]() {
304 std::this_thread::sleep_for(std::chrono::nanoseconds(sleepTime));
305 returnResponse(callback, storedResponses);
306 mThreadCount--;
307 mCv.notify_one();
308 });
309 // Detach the thread here so we do not have to maintain the thread object. mThreadCount
310 // and mCv make sure we wait for all threads to end before we exit.
311 t.detach();
312 return StatusCode::OK;
313
314 } else {
315 return returnResponse(callback, storedResponses);
316 }
317 }
318
319 template StatusCode MockVehicleHardware::handleRequestsLocked<GetValueRequest, GetValueResult>(
320 const char* functionName,
321 std::shared_ptr<const std::function<void(std::vector<GetValueResult>)>> callback,
322 const std::vector<GetValueRequest>& requests,
323 std::list<std::vector<GetValueRequest>>* storedRequests,
324 std::list<std::vector<GetValueResult>>* storedResponses) const;
325
326 template StatusCode MockVehicleHardware::handleRequestsLocked<SetValueRequest, SetValueResult>(
327 const char* functionName,
328 std::shared_ptr<const std::function<void(std::vector<SetValueResult>)>> callback,
329 const std::vector<SetValueRequest>& requests,
330 std::list<std::vector<SetValueRequest>>* storedRequests,
331 std::list<std::vector<SetValueResult>>* storedResponses) const;
332
sendOnPropertySetErrorEvent(const std::vector<SetValueErrorEvent> & errorEvents)333 void MockVehicleHardware::sendOnPropertySetErrorEvent(
334 const std::vector<SetValueErrorEvent>& errorEvents) {
335 std::scoped_lock<std::mutex> lockGuard(mLock);
336 (*mPropertySetErrorCallback)(errorEvents);
337 }
338
339 } // namespace vehicle
340 } // namespace automotive
341 } // namespace hardware
342 } // namespace android
343