/* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "ConnectedClient.h" #include "ParcelableUtils.h" #include #include #include #include #include namespace android { namespace hardware { namespace automotive { namespace vehicle { namespace { using ::aidl::android::hardware::automotive::vehicle::GetValueResult; using ::aidl::android::hardware::automotive::vehicle::GetValueResults; using ::aidl::android::hardware::automotive::vehicle::IVehicleCallback; using ::aidl::android::hardware::automotive::vehicle::SetValueResult; using ::aidl::android::hardware::automotive::vehicle::SetValueResults; using ::aidl::android::hardware::automotive::vehicle::StatusCode; using ::aidl::android::hardware::automotive::vehicle::VehiclePropError; using ::aidl::android::hardware::automotive::vehicle::VehiclePropErrors; using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue; using ::aidl::android::hardware::automotive::vehicle::VehiclePropValues; using ::android::base::Result; using ::ndk::ScopedAStatus; // A function to call the specific callback based on results type. template ScopedAStatus callCallback(std::shared_ptr callback, const T& results); template <> ScopedAStatus callCallback(std::shared_ptr callback, const GetValueResults& results) { return callback->onGetValues(results); } template <> ScopedAStatus callCallback(std::shared_ptr callback, const SetValueResults& results) { return callback->onSetValues(results); } // Send a single GetValue/SetValue result through the callback. template void sendGetOrSetValueResult(std::shared_ptr callback, const ResultType& result) { ResultsType parcelableResults; parcelableResults.payloads.resize(1); parcelableResults.payloads[0] = result; if (ScopedAStatus callbackStatus = callCallback(callback, parcelableResults); !callbackStatus.isOk()) { ALOGE("failed to call GetOrSetValueResult callback, client ID: %p, error: %s, " "exception: %d, service specific error: %d", callback->asBinder().get(), callbackStatus.getMessage(), callbackStatus.getExceptionCode(), callbackStatus.getServiceSpecificError()); } } // Send all the GetValue/SetValue results through callback, one result in each callback invocation. template void sendGetOrSetValueResultsSeparately(std::shared_ptr callback, const std::vector& results) { for (const auto& result : results) { sendGetOrSetValueResult(callback, result); } } // Send all the GetValue/SetValue results through callback in a single callback invocation. template void sendGetOrSetValueResults(std::shared_ptr callback, std::vector&& results) { ResultsType parcelableResults; ScopedAStatus status = vectorToStableLargeParcelable(std::move(results), &parcelableResults); if (status.isOk()) { if (ScopedAStatus callbackStatus = callCallback(callback, parcelableResults); !callbackStatus.isOk()) { ALOGE("failed to call GetOrSetValueResults callback, client ID: %p, error: %s, " "exception: %d, service specific error: %d", callback->asBinder().get(), callbackStatus.getMessage(), callbackStatus.getExceptionCode(), callbackStatus.getServiceSpecificError()); } return; } int statusCode = status.getServiceSpecificError(); ALOGE("failed to marshal result into large parcelable, error: " "%s, code: %d", status.getMessage(), statusCode); sendGetOrSetValueResultsSeparately(callback, parcelableResults.payloads); } // The timeout callback for GetValues/SetValues. template void onTimeout( std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback, const std::unordered_set& timeoutIds) { std::vector timeoutResults; for (int64_t requestId : timeoutIds) { ALOGD("hardware request timeout, request ID: %" PRId64, requestId); timeoutResults.push_back({ .requestId = requestId, .status = StatusCode::TRY_AGAIN, }); } sendGetOrSetValueResults(callback, std::move(timeoutResults)); } // The on-results callback for GetValues/SetValues. template void getOrSetValuesCallback( const void* clientId, std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback, std::vector&& results, std::shared_ptr requestPool) { std::unordered_set requestIds; for (const auto& result : results) { requestIds.insert(result.requestId); } auto finishedRequests = requestPool->tryFinishRequests(clientId, requestIds); auto it = results.begin(); while (it != results.end()) { int64_t requestId = it->requestId; if (finishedRequests.find(requestId) == finishedRequests.end()) { ALOGD("no pending request for the result from hardware, " "possibly already time-out, ID: %" PRId64, requestId); it = results.erase(it); } else { it++; } } if (!results.empty()) { sendGetOrSetValueResults(callback, std::move(results)); } } // Specify the functions for GetValues and SetValues types. template void sendGetOrSetValueResult( std::shared_ptr callback, const GetValueResult& result); template void sendGetOrSetValueResult( std::shared_ptr callback, const SetValueResult& result); template void sendGetOrSetValueResults( std::shared_ptr callback, std::vector&& results); template void sendGetOrSetValueResults( std::shared_ptr callback, std::vector&& results); template void sendGetOrSetValueResultsSeparately( std::shared_ptr callback, const std::vector& results); template void sendGetOrSetValueResultsSeparately( std::shared_ptr callback, const std::vector& results); template void onTimeout( std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback, const std::unordered_set& timeoutIds); template void onTimeout( std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback, const std::unordered_set& timeoutIds); template void getOrSetValuesCallback( const void* clientId, std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback, std::vector&& results, std::shared_ptr requestPool); template void getOrSetValuesCallback( const void* clientId, std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback, std::vector&& results, std::shared_ptr requestPool); } // namespace ConnectedClient::ConnectedClient(std::shared_ptr requestPool, std::shared_ptr callback) : mRequestPool(requestPool), mCallback(callback) {} const void* ConnectedClient::id() { return reinterpret_cast(this); } VhalResult ConnectedClient::addRequests(const std::unordered_set& requestIds) { return mRequestPool->addRequests(id(), requestIds, getTimeoutCallback()); } std::unordered_set ConnectedClient::tryFinishRequests( const std::unordered_set& requestIds) { return mRequestPool->tryFinishRequests(id(), requestIds); } template GetSetValuesClient::GetSetValuesClient( std::shared_ptr requestPool, std::shared_ptr callback) : ConnectedClient(requestPool, callback) { mTimeoutCallback = std::make_shared( [callback](const std::unordered_set& timeoutIds) { return onTimeout(callback, timeoutIds); }); auto requestPoolCopy = mRequestPool; const void* clientId = id(); mResultCallback = std::make_shared)>>( [clientId, callback, requestPoolCopy](std::vector results) { return getOrSetValuesCallback( clientId, callback, std::move(results), requestPoolCopy); }); } template std::shared_ptr)>> GetSetValuesClient::getResultCallback() { return mResultCallback; } template std::shared_ptr GetSetValuesClient::getTimeoutCallback() { return mTimeoutCallback; } template void GetSetValuesClient::sendResults(std::vector&& results) { return sendGetOrSetValueResults(mCallback, std::move(results)); } template void GetSetValuesClient::sendResultsSeparately( const std::vector& results) { return sendGetOrSetValueResultsSeparately(mCallback, results); } template class GetSetValuesClient; template class GetSetValuesClient; void SubscriptionClient::sendUpdatedValues(std::shared_ptr callback, std::vector&& updatedValues) { if (updatedValues.empty()) { return; } // TODO(b/205189110): Use memory pool here and fill in sharedMemoryId. VehiclePropValues vehiclePropValues; int32_t sharedMemoryFileCount = 0; ScopedAStatus status = vectorToStableLargeParcelable(std::move(updatedValues), &vehiclePropValues); if (!status.isOk()) { int statusCode = status.getServiceSpecificError(); ALOGE("subscribe: failed to marshal result into large parcelable, error: " "%s, code: %d", status.getMessage(), statusCode); return; } if (ScopedAStatus callbackStatus = callback->onPropertyEvent(vehiclePropValues, sharedMemoryFileCount); !callbackStatus.isOk()) { ALOGE("subscribe: failed to call onPropertyEvent callback, client ID: %p, error: %s, " "exception: %d, service specific error: %d", callback->asBinder().get(), callbackStatus.getMessage(), callbackStatus.getExceptionCode(), callbackStatus.getServiceSpecificError()); } } void SubscriptionClient::sendPropertySetErrors(std::shared_ptr callback, std::vector&& vehiclePropErrors) { if (vehiclePropErrors.empty()) { return; } VehiclePropErrors vehiclePropErrorsLargeParcelable; ScopedAStatus status = vectorToStableLargeParcelable(std::move(vehiclePropErrors), &vehiclePropErrorsLargeParcelable); if (!status.isOk()) { int statusCode = status.getServiceSpecificError(); ALOGE("subscribe: failed to marshal result into large parcelable, error: " "%s, code: %d", status.getMessage(), statusCode); return; } if (ScopedAStatus callbackStatus = callback->onPropertySetError(vehiclePropErrorsLargeParcelable); !callbackStatus.isOk()) { ALOGE("subscribe: failed to call onPropertySetError callback, client ID: %p, error: %s, " "exception: %d, service specific error: %d", callback->asBinder().get(), callbackStatus.getMessage(), callbackStatus.getExceptionCode(), callbackStatus.getServiceSpecificError()); } } } // namespace vehicle } // namespace automotive } // namespace hardware } // namespace android