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