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