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 "ConnectedClient.h"
18 #include "ParcelableUtils.h"
19
20 #include <VehicleHalTypes.h>
21
22 #include <utils/Log.h>
23
24 #include <inttypes.h>
25 #include <unordered_set>
26 #include <vector>
27
28 namespace android {
29 namespace hardware {
30 namespace automotive {
31 namespace vehicle {
32
33 namespace {
34
35 using ::aidl::android::hardware::automotive::vehicle::GetValueResult;
36 using ::aidl::android::hardware::automotive::vehicle::GetValueResults;
37 using ::aidl::android::hardware::automotive::vehicle::IVehicleCallback;
38 using ::aidl::android::hardware::automotive::vehicle::SetValueResult;
39 using ::aidl::android::hardware::automotive::vehicle::SetValueResults;
40 using ::aidl::android::hardware::automotive::vehicle::StatusCode;
41 using ::aidl::android::hardware::automotive::vehicle::VehiclePropError;
42 using ::aidl::android::hardware::automotive::vehicle::VehiclePropErrors;
43 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
44 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValues;
45 using ::android::base::Result;
46 using ::ndk::ScopedAStatus;
47
48 // A function to call the specific callback based on results type.
49 template <class T>
50 ScopedAStatus callCallback(std::shared_ptr<IVehicleCallback> callback, const T& results);
51
52 template <>
callCallback(std::shared_ptr<IVehicleCallback> callback,const GetValueResults & results)53 ScopedAStatus callCallback<GetValueResults>(std::shared_ptr<IVehicleCallback> callback,
54 const GetValueResults& results) {
55 return callback->onGetValues(results);
56 }
57
58 template <>
callCallback(std::shared_ptr<IVehicleCallback> callback,const SetValueResults & results)59 ScopedAStatus callCallback<SetValueResults>(std::shared_ptr<IVehicleCallback> callback,
60 const SetValueResults& results) {
61 return callback->onSetValues(results);
62 }
63
64 // Send a single GetValue/SetValue result through the callback.
65 template <class ResultType, class ResultsType>
sendGetOrSetValueResult(std::shared_ptr<IVehicleCallback> callback,const ResultType & result)66 void sendGetOrSetValueResult(std::shared_ptr<IVehicleCallback> callback, const ResultType& result) {
67 ResultsType parcelableResults;
68 parcelableResults.payloads.resize(1);
69 parcelableResults.payloads[0] = result;
70 if (ScopedAStatus callbackStatus = callCallback(callback, parcelableResults);
71 !callbackStatus.isOk()) {
72 ALOGE("failed to call GetOrSetValueResult callback, client ID: %p, error: %s, "
73 "exception: %d, service specific error: %d",
74 callback->asBinder().get(), callbackStatus.getMessage(),
75 callbackStatus.getExceptionCode(), callbackStatus.getServiceSpecificError());
76 }
77 }
78
79 // Send all the GetValue/SetValue results through callback, one result in each callback invocation.
80 template <class ResultType, class ResultsType>
sendGetOrSetValueResultsSeparately(std::shared_ptr<IVehicleCallback> callback,const std::vector<ResultType> & results)81 void sendGetOrSetValueResultsSeparately(std::shared_ptr<IVehicleCallback> callback,
82 const std::vector<ResultType>& results) {
83 for (const auto& result : results) {
84 sendGetOrSetValueResult<ResultType, ResultsType>(callback, result);
85 }
86 }
87
88 // Send all the GetValue/SetValue results through callback in a single callback invocation.
89 template <class ResultType, class ResultsType>
sendGetOrSetValueResults(std::shared_ptr<IVehicleCallback> callback,std::vector<ResultType> && results)90 void sendGetOrSetValueResults(std::shared_ptr<IVehicleCallback> callback,
91 std::vector<ResultType>&& results) {
92 ResultsType parcelableResults;
93 ScopedAStatus status = vectorToStableLargeParcelable(std::move(results), &parcelableResults);
94 if (status.isOk()) {
95 if (ScopedAStatus callbackStatus = callCallback(callback, parcelableResults);
96 !callbackStatus.isOk()) {
97 ALOGE("failed to call GetOrSetValueResults callback, client ID: %p, error: %s, "
98 "exception: %d, service specific error: %d",
99 callback->asBinder().get(), callbackStatus.getMessage(),
100 callbackStatus.getExceptionCode(), callbackStatus.getServiceSpecificError());
101 }
102 return;
103 }
104 int statusCode = status.getServiceSpecificError();
105 ALOGE("failed to marshal result into large parcelable, error: "
106 "%s, code: %d",
107 status.getMessage(), statusCode);
108 sendGetOrSetValueResultsSeparately<ResultType, ResultsType>(callback,
109 parcelableResults.payloads);
110 }
111
112 // The timeout callback for GetValues/SetValues.
113 template <class ResultType, class ResultsType>
onTimeout(std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback,const std::unordered_set<int64_t> & timeoutIds)114 void onTimeout(
115 std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback,
116 const std::unordered_set<int64_t>& timeoutIds) {
117 std::vector<ResultType> timeoutResults;
118 for (int64_t requestId : timeoutIds) {
119 ALOGD("hardware request timeout, request ID: %" PRId64, requestId);
120 timeoutResults.push_back({
121 .requestId = requestId,
122 .status = StatusCode::TRY_AGAIN,
123 });
124 }
125 sendGetOrSetValueResults<ResultType, ResultsType>(callback, std::move(timeoutResults));
126 }
127
128 // The on-results callback for GetValues/SetValues.
129 template <class ResultType, class ResultsType>
getOrSetValuesCallback(const void * clientId,std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback,std::vector<ResultType> && results,std::shared_ptr<PendingRequestPool> requestPool)130 void getOrSetValuesCallback(
131 const void* clientId,
132 std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback,
133 std::vector<ResultType>&& results, std::shared_ptr<PendingRequestPool> requestPool) {
134 std::unordered_set<int64_t> requestIds;
135 for (const auto& result : results) {
136 requestIds.insert(result.requestId);
137 }
138
139 auto finishedRequests = requestPool->tryFinishRequests(clientId, requestIds);
140
141 auto it = results.begin();
142 while (it != results.end()) {
143 int64_t requestId = it->requestId;
144 if (finishedRequests.find(requestId) == finishedRequests.end()) {
145 ALOGD("no pending request for the result from hardware, "
146 "possibly already time-out, ID: %" PRId64,
147 requestId);
148 it = results.erase(it);
149 } else {
150 it++;
151 }
152 }
153
154 if (!results.empty()) {
155 sendGetOrSetValueResults<ResultType, ResultsType>(callback, std::move(results));
156 }
157 }
158
159 // Specify the functions for GetValues and SetValues types.
160 template void sendGetOrSetValueResult<GetValueResult, GetValueResults>(
161 std::shared_ptr<IVehicleCallback> callback, const GetValueResult& result);
162 template void sendGetOrSetValueResult<SetValueResult, SetValueResults>(
163 std::shared_ptr<IVehicleCallback> callback, const SetValueResult& result);
164
165 template void sendGetOrSetValueResults<GetValueResult, GetValueResults>(
166 std::shared_ptr<IVehicleCallback> callback, std::vector<GetValueResult>&& results);
167 template void sendGetOrSetValueResults<SetValueResult, SetValueResults>(
168 std::shared_ptr<IVehicleCallback> callback, std::vector<SetValueResult>&& results);
169
170 template void sendGetOrSetValueResultsSeparately<GetValueResult, GetValueResults>(
171 std::shared_ptr<IVehicleCallback> callback, const std::vector<GetValueResult>& results);
172 template void sendGetOrSetValueResultsSeparately<SetValueResult, SetValueResults>(
173 std::shared_ptr<IVehicleCallback> callback, const std::vector<SetValueResult>& results);
174
175 template void onTimeout<GetValueResult, GetValueResults>(
176 std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback,
177 const std::unordered_set<int64_t>& timeoutIds);
178 template void onTimeout<SetValueResult, SetValueResults>(
179 std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback,
180 const std::unordered_set<int64_t>& timeoutIds);
181
182 template void getOrSetValuesCallback<GetValueResult, GetValueResults>(
183 const void* clientId,
184 std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback,
185 std::vector<GetValueResult>&& results, std::shared_ptr<PendingRequestPool> requestPool);
186 template void getOrSetValuesCallback<SetValueResult, SetValueResults>(
187 const void* clientId,
188 std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback,
189 std::vector<SetValueResult>&& results, std::shared_ptr<PendingRequestPool> requestPool);
190
191 } // namespace
192
ConnectedClient(std::shared_ptr<PendingRequestPool> requestPool,std::shared_ptr<IVehicleCallback> callback)193 ConnectedClient::ConnectedClient(std::shared_ptr<PendingRequestPool> requestPool,
194 std::shared_ptr<IVehicleCallback> callback)
195 : mRequestPool(requestPool), mCallback(callback) {}
196
id()197 const void* ConnectedClient::id() {
198 return reinterpret_cast<const void*>(this);
199 }
200
addRequests(const std::unordered_set<int64_t> & requestIds)201 VhalResult<void> ConnectedClient::addRequests(const std::unordered_set<int64_t>& requestIds) {
202 return mRequestPool->addRequests(id(), requestIds, getTimeoutCallback());
203 }
204
tryFinishRequests(const std::unordered_set<int64_t> & requestIds)205 std::unordered_set<int64_t> ConnectedClient::tryFinishRequests(
206 const std::unordered_set<int64_t>& requestIds) {
207 return mRequestPool->tryFinishRequests(id(), requestIds);
208 }
209
210 template <class ResultType, class ResultsType>
GetSetValuesClient(std::shared_ptr<PendingRequestPool> requestPool,std::shared_ptr<IVehicleCallback> callback)211 GetSetValuesClient<ResultType, ResultsType>::GetSetValuesClient(
212 std::shared_ptr<PendingRequestPool> requestPool, std::shared_ptr<IVehicleCallback> callback)
213 : ConnectedClient(requestPool, callback) {
214 mTimeoutCallback = std::make_shared<const PendingRequestPool::TimeoutCallbackFunc>(
215 [callback](const std::unordered_set<int64_t>& timeoutIds) {
216 return onTimeout<ResultType, ResultsType>(callback, timeoutIds);
217 });
218 auto requestPoolCopy = mRequestPool;
219 const void* clientId = id();
220 mResultCallback = std::make_shared<const std::function<void(std::vector<ResultType>)>>(
221 [clientId, callback, requestPoolCopy](std::vector<ResultType> results) {
222 return getOrSetValuesCallback<ResultType, ResultsType>(
223 clientId, callback, std::move(results), requestPoolCopy);
224 });
225 }
226
227 template <class ResultType, class ResultsType>
228 std::shared_ptr<const std::function<void(std::vector<ResultType>)>>
getResultCallback()229 GetSetValuesClient<ResultType, ResultsType>::getResultCallback() {
230 return mResultCallback;
231 }
232
233 template <class ResultType, class ResultsType>
234 std::shared_ptr<const PendingRequestPool::TimeoutCallbackFunc>
getTimeoutCallback()235 GetSetValuesClient<ResultType, ResultsType>::getTimeoutCallback() {
236 return mTimeoutCallback;
237 }
238
239 template <class ResultType, class ResultsType>
sendResults(std::vector<ResultType> && results)240 void GetSetValuesClient<ResultType, ResultsType>::sendResults(std::vector<ResultType>&& results) {
241 return sendGetOrSetValueResults<ResultType, ResultsType>(mCallback, std::move(results));
242 }
243
244 template <class ResultType, class ResultsType>
sendResultsSeparately(const std::vector<ResultType> & results)245 void GetSetValuesClient<ResultType, ResultsType>::sendResultsSeparately(
246 const std::vector<ResultType>& results) {
247 return sendGetOrSetValueResultsSeparately<ResultType, ResultsType>(mCallback, results);
248 }
249
250 template class GetSetValuesClient<GetValueResult, GetValueResults>;
251 template class GetSetValuesClient<SetValueResult, SetValueResults>;
252
sendUpdatedValues(std::shared_ptr<IVehicleCallback> callback,std::vector<VehiclePropValue> && updatedValues)253 void SubscriptionClient::sendUpdatedValues(std::shared_ptr<IVehicleCallback> callback,
254 std::vector<VehiclePropValue>&& updatedValues) {
255 if (updatedValues.empty()) {
256 return;
257 }
258
259 // TODO(b/205189110): Use memory pool here and fill in sharedMemoryId.
260 VehiclePropValues vehiclePropValues;
261 int32_t sharedMemoryFileCount = 0;
262 ScopedAStatus status =
263 vectorToStableLargeParcelable(std::move(updatedValues), &vehiclePropValues);
264 if (!status.isOk()) {
265 int statusCode = status.getServiceSpecificError();
266 ALOGE("subscribe: failed to marshal result into large parcelable, error: "
267 "%s, code: %d",
268 status.getMessage(), statusCode);
269 return;
270 }
271
272 if (ScopedAStatus callbackStatus =
273 callback->onPropertyEvent(vehiclePropValues, sharedMemoryFileCount);
274 !callbackStatus.isOk()) {
275 ALOGE("subscribe: failed to call onPropertyEvent callback, client ID: %p, error: %s, "
276 "exception: %d, service specific error: %d",
277 callback->asBinder().get(), callbackStatus.getMessage(),
278 callbackStatus.getExceptionCode(), callbackStatus.getServiceSpecificError());
279 }
280 }
281
sendPropertySetErrors(std::shared_ptr<IVehicleCallback> callback,std::vector<VehiclePropError> && vehiclePropErrors)282 void SubscriptionClient::sendPropertySetErrors(std::shared_ptr<IVehicleCallback> callback,
283 std::vector<VehiclePropError>&& vehiclePropErrors) {
284 if (vehiclePropErrors.empty()) {
285 return;
286 }
287
288 VehiclePropErrors vehiclePropErrorsLargeParcelable;
289 ScopedAStatus status = vectorToStableLargeParcelable(std::move(vehiclePropErrors),
290 &vehiclePropErrorsLargeParcelable);
291 if (!status.isOk()) {
292 int statusCode = status.getServiceSpecificError();
293 ALOGE("subscribe: failed to marshal result into large parcelable, error: "
294 "%s, code: %d",
295 status.getMessage(), statusCode);
296 return;
297 }
298
299 if (ScopedAStatus callbackStatus =
300 callback->onPropertySetError(vehiclePropErrorsLargeParcelable);
301 !callbackStatus.isOk()) {
302 ALOGE("subscribe: failed to call onPropertySetError callback, client ID: %p, error: %s, "
303 "exception: %d, service specific error: %d",
304 callback->asBinder().get(), callbackStatus.getMessage(),
305 callbackStatus.getExceptionCode(), callbackStatus.getServiceSpecificError());
306 }
307 }
308
309 } // namespace vehicle
310 } // namespace automotive
311 } // namespace hardware
312 } // namespace android
313