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>)133 void MockVehicleHardware::registerOnPropertySetErrorEvent(
134 std::unique_ptr<const PropertySetErrorCallback>) {
135 // TODO(b/200737967): mock this.
136 }
137
setPropertyConfigs(const std::vector<VehiclePropConfig> & configs)138 void MockVehicleHardware::setPropertyConfigs(const std::vector<VehiclePropConfig>& configs) {
139 std::scoped_lock<std::mutex> lockGuard(mLock);
140 mPropertyConfigs = configs;
141 }
142
addGetValueResponses(const std::vector<GetValueResult> & responses)143 void MockVehicleHardware::addGetValueResponses(const std::vector<GetValueResult>& responses) {
144 std::scoped_lock<std::mutex> lockGuard(mLock);
145 mGetValueResponses.push_back(responses);
146 }
147
addSetValueResponses(const std::vector<SetValueResult> & responses)148 void MockVehicleHardware::addSetValueResponses(const std::vector<SetValueResult>& responses) {
149 std::scoped_lock<std::mutex> lockGuard(mLock);
150 mSetValueResponses.push_back(responses);
151 }
152
setGetValueResponder(std::function<StatusCode (std::shared_ptr<const GetValuesCallback>,const std::vector<GetValueRequest> &)> && responder)153 void MockVehicleHardware::setGetValueResponder(
154 std::function<StatusCode(std::shared_ptr<const GetValuesCallback>,
155 const std::vector<GetValueRequest>&)>&& responder) {
156 std::scoped_lock<std::mutex> lockGuard(mLock);
157 mGetValueResponder = responder;
158 }
159
nextGetValueRequests()160 std::vector<GetValueRequest> MockVehicleHardware::nextGetValueRequests() {
161 std::scoped_lock<std::mutex> lockGuard(mLock);
162 std::optional<std::vector<GetValueRequest>> request = pop(mGetValueRequests);
163 if (!request.has_value()) {
164 return std::vector<GetValueRequest>();
165 }
166 return std::move(request.value());
167 }
168
nextSetValueRequests()169 std::vector<SetValueRequest> MockVehicleHardware::nextSetValueRequests() {
170 std::scoped_lock<std::mutex> lockGuard(mLock);
171 std::optional<std::vector<SetValueRequest>> request = pop(mSetValueRequests);
172 if (!request.has_value()) {
173 return std::vector<SetValueRequest>();
174 }
175 return std::move(request.value());
176 }
177
setStatus(const char * functionName,StatusCode status)178 void MockVehicleHardware::setStatus(const char* functionName, StatusCode status) {
179 std::scoped_lock<std::mutex> lockGuard(mLock);
180 mStatusByFunctions[functionName] = status;
181 }
182
setSleepTime(int64_t timeInNano)183 void MockVehicleHardware::setSleepTime(int64_t timeInNano) {
184 std::scoped_lock<std::mutex> lockGuard(mLock);
185 mSleepTime = timeInNano;
186 }
187
188 template <class ResultType>
returnResponse(std::shared_ptr<const std::function<void (std::vector<ResultType>)>> callback,std::list<std::vector<ResultType>> * storedResponses) const189 StatusCode MockVehicleHardware::returnResponse(
190 std::shared_ptr<const std::function<void(std::vector<ResultType>)>> callback,
191 std::list<std::vector<ResultType>>* storedResponses) const {
192 if (storedResponses->size() > 0) {
193 (*callback)(std::move(storedResponses->front()));
194 storedResponses->pop_front();
195 return StatusCode::OK;
196 } else {
197 ALOGE("no more response");
198 return StatusCode::INTERNAL_ERROR;
199 }
200 }
201
202 template StatusCode MockVehicleHardware::returnResponse<GetValueResult>(
203 std::shared_ptr<const std::function<void(std::vector<GetValueResult>)>> callback,
204 std::list<std::vector<GetValueResult>>* storedResponses) const;
205
206 template StatusCode MockVehicleHardware::returnResponse<SetValueResult>(
207 std::shared_ptr<const std::function<void(std::vector<SetValueResult>)>> callback,
208 std::list<std::vector<SetValueResult>>* storedResponses) const;
209
210 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) const211 StatusCode MockVehicleHardware::handleRequestsLocked(
212 const char* functionName,
213 std::shared_ptr<const std::function<void(std::vector<ResultType>)>> callback,
214 const std::vector<RequestType>& requests,
215 std::list<std::vector<RequestType>>* storedRequests,
216 std::list<std::vector<ResultType>>* storedResponses) const {
217 storedRequests->push_back(requests);
218 if (auto it = mStatusByFunctions.find(functionName); it != mStatusByFunctions.end()) {
219 if (StatusCode status = it->second; status != StatusCode::OK) {
220 return status;
221 }
222 }
223
224 if (mSleepTime != 0) {
225 int64_t sleepTime = mSleepTime;
226 mThreadCount++;
227 std::thread t([this, callback, sleepTime, storedResponses]() {
228 std::this_thread::sleep_for(std::chrono::nanoseconds(sleepTime));
229 returnResponse(callback, storedResponses);
230 mThreadCount--;
231 mCv.notify_one();
232 });
233 // Detach the thread here so we do not have to maintain the thread object. mThreadCount
234 // and mCv make sure we wait for all threads to end before we exit.
235 t.detach();
236 return StatusCode::OK;
237
238 } else {
239 return returnResponse(callback, storedResponses);
240 }
241 }
242
243 template StatusCode MockVehicleHardware::handleRequestsLocked<GetValueRequest, GetValueResult>(
244 const char* functionName,
245 std::shared_ptr<const std::function<void(std::vector<GetValueResult>)>> callback,
246 const std::vector<GetValueRequest>& requests,
247 std::list<std::vector<GetValueRequest>>* storedRequests,
248 std::list<std::vector<GetValueResult>>* storedResponses) const;
249
250 template StatusCode MockVehicleHardware::handleRequestsLocked<SetValueRequest, SetValueResult>(
251 const char* functionName,
252 std::shared_ptr<const std::function<void(std::vector<SetValueResult>)>> callback,
253 const std::vector<SetValueRequest>& requests,
254 std::list<std::vector<SetValueRequest>>* storedRequests,
255 std::list<std::vector<SetValueResult>>* storedResponses) const;
256
257 } // namespace vehicle
258 } // namespace automotive
259 } // namespace hardware
260 } // namespace android
261