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