• 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::VehiclePropConfig;
33 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
34 
MockVehicleHardware()35 MockVehicleHardware::MockVehicleHardware() {
36     mRecurrentTimer = std::make_unique<RecurrentTimer>();
37 }
38 
~MockVehicleHardware()39 MockVehicleHardware::~MockVehicleHardware() {
40     std::unique_lock<std::mutex> lk(mLock);
41     mCv.wait(lk, [this] { return mThreadCount == 0; });
42     mRecurrentTimer.reset();
43 }
44 
getAllPropertyConfigs() const45 std::vector<VehiclePropConfig> MockVehicleHardware::getAllPropertyConfigs() const {
46     std::scoped_lock<std::mutex> lockGuard(mLock);
47     return mPropertyConfigs;
48 }
49 
setValues(std::shared_ptr<const SetValuesCallback> callback,const std::vector<SetValueRequest> & requests)50 StatusCode MockVehicleHardware::setValues(std::shared_ptr<const SetValuesCallback> callback,
51                                           const std::vector<SetValueRequest>& requests) {
52     std::scoped_lock<std::mutex> lockGuard(mLock);
53     if (StatusCode status = handleRequestsLocked(__func__, callback, requests, &mSetValueRequests,
54                                                  &mSetValueResponses);
55         status != StatusCode::OK) {
56         return status;
57     }
58     if (mPropertyChangeCallback == nullptr) {
59         return StatusCode::OK;
60     }
61     std::vector<VehiclePropValue> values;
62     for (auto& request : requests) {
63         values.push_back(request.value);
64     }
65     (*mPropertyChangeCallback)(values);
66     return StatusCode::OK;
67 }
68 
getValues(std::shared_ptr<const GetValuesCallback> callback,const std::vector<GetValueRequest> & requests) const69 StatusCode MockVehicleHardware::getValues(std::shared_ptr<const GetValuesCallback> callback,
70                                           const std::vector<GetValueRequest>& requests) const {
71     std::scoped_lock<std::mutex> lockGuard(mLock);
72     if (mGetValueResponder != nullptr) {
73         return mGetValueResponder(callback, requests);
74     }
75     return handleRequestsLocked(__func__, callback, requests, &mGetValueRequests,
76                                 &mGetValueResponses);
77 }
78 
setDumpResult(DumpResult result)79 void MockVehicleHardware::setDumpResult(DumpResult result) {
80     mDumpResult = result;
81 }
82 
dump(const std::vector<std::string> &)83 DumpResult MockVehicleHardware::dump(const std::vector<std::string>&) {
84     return mDumpResult;
85 }
86 
checkHealth()87 StatusCode MockVehicleHardware::checkHealth() {
88     return StatusCode::OK;
89 }
90 
updateSampleRate(int32_t propId,int32_t areaId,float sampleRate)91 StatusCode MockVehicleHardware::updateSampleRate(int32_t propId, int32_t areaId, float sampleRate) {
92     std::shared_ptr<std::function<void()>> action;
93 
94     {
95         std::scoped_lock<std::mutex> lockGuard(mLock);
96         if (mRecurrentActions[propId][areaId] != nullptr) {
97             // Remove the previous action register for this [propId, areaId].
98             mRecurrentTimer->unregisterTimerCallback(mRecurrentActions[propId][areaId]);
99         }
100         if (sampleRate == 0) {
101             return StatusCode::OK;
102         }
103 
104         // We are sure 'propertyChangeCallback' would be alive because we would unregister timer
105         // before destroying 'this' which owns mPropertyChangeCallback.
106         const PropertyChangeCallback* propertyChangeCallback = mPropertyChangeCallback.get();
107         action = std::make_shared<std::function<void()>>([propertyChangeCallback, propId, areaId] {
108             std::vector<VehiclePropValue> values = {
109                     {
110                             .prop = propId,
111                             .areaId = areaId,
112                     },
113             };
114             (*propertyChangeCallback)(values);
115         });
116         // Store the action in a map so that we could remove the action later.
117         mRecurrentActions[propId][areaId] = action;
118     }
119 
120     // In mock implementation, we generate a new property change event for this property at sample
121     // rate.
122     int64_t interval = static_cast<int64_t>(1'000'000'000. / sampleRate);
123     mRecurrentTimer->registerTimerCallback(interval, action);
124     return StatusCode::OK;
125 }
126 
registerOnPropertyChangeEvent(std::unique_ptr<const PropertyChangeCallback> callback)127 void MockVehicleHardware::registerOnPropertyChangeEvent(
128         std::unique_ptr<const PropertyChangeCallback> callback) {
129     std::scoped_lock<std::mutex> lockGuard(mLock);
130     mPropertyChangeCallback = std::move(callback);
131 }
132 
registerOnPropertySetErrorEvent(std::unique_ptr<const PropertySetErrorCallback> callback)133 void MockVehicleHardware::registerOnPropertySetErrorEvent(
134         std::unique_ptr<const PropertySetErrorCallback> callback) {
135     std::scoped_lock<std::mutex> lockGuard(mLock);
136     mPropertySetErrorCallback = std::move(callback);
137 }
138 
setPropertyConfigs(const std::vector<VehiclePropConfig> & configs)139 void MockVehicleHardware::setPropertyConfigs(const std::vector<VehiclePropConfig>& configs) {
140     std::scoped_lock<std::mutex> lockGuard(mLock);
141     mPropertyConfigs = configs;
142 }
143 
addGetValueResponses(const std::vector<GetValueResult> & responses)144 void MockVehicleHardware::addGetValueResponses(const std::vector<GetValueResult>& responses) {
145     std::scoped_lock<std::mutex> lockGuard(mLock);
146     mGetValueResponses.push_back(responses);
147 }
148 
addSetValueResponses(const std::vector<SetValueResult> & responses)149 void MockVehicleHardware::addSetValueResponses(const std::vector<SetValueResult>& responses) {
150     std::scoped_lock<std::mutex> lockGuard(mLock);
151     mSetValueResponses.push_back(responses);
152 }
153 
setGetValueResponder(std::function<StatusCode (std::shared_ptr<const GetValuesCallback>,const std::vector<GetValueRequest> &)> && responder)154 void MockVehicleHardware::setGetValueResponder(
155         std::function<StatusCode(std::shared_ptr<const GetValuesCallback>,
156                                  const std::vector<GetValueRequest>&)>&& responder) {
157     std::scoped_lock<std::mutex> lockGuard(mLock);
158     mGetValueResponder = responder;
159 }
160 
nextGetValueRequests()161 std::vector<GetValueRequest> MockVehicleHardware::nextGetValueRequests() {
162     std::scoped_lock<std::mutex> lockGuard(mLock);
163     std::optional<std::vector<GetValueRequest>> request = pop(mGetValueRequests);
164     if (!request.has_value()) {
165         return std::vector<GetValueRequest>();
166     }
167     return std::move(request.value());
168 }
169 
nextSetValueRequests()170 std::vector<SetValueRequest> MockVehicleHardware::nextSetValueRequests() {
171     std::scoped_lock<std::mutex> lockGuard(mLock);
172     std::optional<std::vector<SetValueRequest>> request = pop(mSetValueRequests);
173     if (!request.has_value()) {
174         return std::vector<SetValueRequest>();
175     }
176     return std::move(request.value());
177 }
178 
setStatus(const char * functionName,StatusCode status)179 void MockVehicleHardware::setStatus(const char* functionName, StatusCode status) {
180     std::scoped_lock<std::mutex> lockGuard(mLock);
181     mStatusByFunctions[functionName] = status;
182 }
183 
setSleepTime(int64_t timeInNano)184 void MockVehicleHardware::setSleepTime(int64_t timeInNano) {
185     std::scoped_lock<std::mutex> lockGuard(mLock);
186     mSleepTime = timeInNano;
187 }
188 
189 template <class ResultType>
returnResponse(std::shared_ptr<const std::function<void (std::vector<ResultType>)>> callback,std::list<std::vector<ResultType>> * storedResponses) const190 StatusCode MockVehicleHardware::returnResponse(
191         std::shared_ptr<const std::function<void(std::vector<ResultType>)>> callback,
192         std::list<std::vector<ResultType>>* storedResponses) const {
193     if (storedResponses->size() > 0) {
194         (*callback)(std::move(storedResponses->front()));
195         storedResponses->pop_front();
196         return StatusCode::OK;
197     } else {
198         ALOGE("no more response");
199         return StatusCode::INTERNAL_ERROR;
200     }
201 }
202 
203 template StatusCode MockVehicleHardware::returnResponse<GetValueResult>(
204         std::shared_ptr<const std::function<void(std::vector<GetValueResult>)>> callback,
205         std::list<std::vector<GetValueResult>>* storedResponses) const;
206 
207 template StatusCode MockVehicleHardware::returnResponse<SetValueResult>(
208         std::shared_ptr<const std::function<void(std::vector<SetValueResult>)>> callback,
209         std::list<std::vector<SetValueResult>>* storedResponses) const;
210 
211 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) const212 StatusCode MockVehicleHardware::handleRequestsLocked(
213         const char* functionName,
214         std::shared_ptr<const std::function<void(std::vector<ResultType>)>> callback,
215         const std::vector<RequestType>& requests,
216         std::list<std::vector<RequestType>>* storedRequests,
217         std::list<std::vector<ResultType>>* storedResponses) const {
218     storedRequests->push_back(requests);
219     if (auto it = mStatusByFunctions.find(functionName); it != mStatusByFunctions.end()) {
220         if (StatusCode status = it->second; status != StatusCode::OK) {
221             return status;
222         }
223     }
224 
225     if (mSleepTime != 0) {
226         int64_t sleepTime = mSleepTime;
227         mThreadCount++;
228         std::thread t([this, callback, sleepTime, storedResponses]() {
229             std::this_thread::sleep_for(std::chrono::nanoseconds(sleepTime));
230             returnResponse(callback, storedResponses);
231             mThreadCount--;
232             mCv.notify_one();
233         });
234         // Detach the thread here so we do not have to maintain the thread object. mThreadCount
235         // and mCv make sure we wait for all threads to end before we exit.
236         t.detach();
237         return StatusCode::OK;
238 
239     } else {
240         return returnResponse(callback, storedResponses);
241     }
242 }
243 
244 template StatusCode MockVehicleHardware::handleRequestsLocked<GetValueRequest, GetValueResult>(
245         const char* functionName,
246         std::shared_ptr<const std::function<void(std::vector<GetValueResult>)>> callback,
247         const std::vector<GetValueRequest>& requests,
248         std::list<std::vector<GetValueRequest>>* storedRequests,
249         std::list<std::vector<GetValueResult>>* storedResponses) const;
250 
251 template StatusCode MockVehicleHardware::handleRequestsLocked<SetValueRequest, SetValueResult>(
252         const char* functionName,
253         std::shared_ptr<const std::function<void(std::vector<SetValueResult>)>> callback,
254         const std::vector<SetValueRequest>& requests,
255         std::list<std::vector<SetValueRequest>>* storedRequests,
256         std::list<std::vector<SetValueResult>>* storedResponses) const;
257 
sendOnPropertySetErrorEvent(const std::vector<SetValueErrorEvent> & errorEvents)258 void MockVehicleHardware::sendOnPropertySetErrorEvent(
259         const std::vector<SetValueErrorEvent>& errorEvents) {
260     std::scoped_lock<std::mutex> lockGuard(mLock);
261     (*mPropertySetErrorCallback)(errorEvents);
262 }
263 
264 }  // namespace vehicle
265 }  // namespace automotive
266 }  // namespace hardware
267 }  // namespace android
268