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