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