| // Copyright (C) 2019 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.c |
| |
| #include "AidlClientImpl.h" |
| |
| #include <vector> |
| |
| #include "OutputConfig.pb.h" |
| #include "PacketDescriptor.pb.h" |
| #include "PipeOptionsConverter.h" |
| #include "StatusUtil.h" |
| |
| #include <aidl/android/automotive/computepipe/runner/PacketDescriptor.h> |
| #include <aidl/android/automotive/computepipe/runner/PacketDescriptorPacketType.h> |
| #include <android-base/logging.h> |
| #include <android/binder_auto_utils.h> |
| |
| namespace android { |
| namespace automotive { |
| namespace computepipe { |
| namespace runner { |
| namespace client_interface { |
| namespace aidl_client { |
| namespace { |
| |
| using ::aidl::android::automotive::computepipe::runner::IPipeStateCallback; |
| using ::aidl::android::automotive::computepipe::runner::IPipeStream; |
| using ::aidl::android::automotive::computepipe::runner::PacketDescriptor; |
| using ::aidl::android::automotive::computepipe::runner::PacketDescriptorPacketType; |
| using ::aidl::android::automotive::computepipe::runner::PipeDescriptor; |
| using ::aidl::android::automotive::computepipe::runner::PipeState; |
| using ::ndk::ScopedAStatus; |
| |
| PipeState ToAidlState(GraphState state) { |
| switch (state) { |
| case RESET: |
| return PipeState::RESET; |
| case CONFIG_DONE: |
| return PipeState::CONFIG_DONE; |
| case RUNNING: |
| return PipeState::RUNNING; |
| case DONE: |
| return PipeState::DONE; |
| case ERR_HALT: |
| default: |
| return PipeState::ERR_HALT; |
| } |
| } |
| |
| void deathNotifier(void* cookie) { |
| CHECK(cookie); |
| AidlClientImpl* iface = static_cast<AidlClientImpl*>(cookie); |
| iface->clientDied(); |
| } |
| |
| Status ToAidlPacketType(proto::PacketType type, PacketDescriptorPacketType* outType) { |
| if (outType == nullptr) { |
| return Status::INTERNAL_ERROR; |
| } |
| switch (type) { |
| case proto::SEMANTIC_DATA: |
| *outType = PacketDescriptorPacketType::SEMANTIC_DATA; |
| return Status::SUCCESS; |
| case proto::PIXEL_DATA: |
| *outType = PacketDescriptorPacketType::PIXEL_DATA; |
| return Status::SUCCESS; |
| default: |
| LOG(ERROR) << "unknown packet type " << type; |
| return Status::INVALID_ARGUMENT; |
| } |
| } |
| |
| } // namespace |
| |
| Status AidlClientImpl::DispatchSemanticData(int32_t streamId, |
| const std::shared_ptr<MemHandle>& packetHandle) { |
| PacketDescriptor desc; |
| |
| if (mPacketHandlers.find(streamId) == mPacketHandlers.end()) { |
| LOG(ERROR) << "Bad streamId"; |
| return Status::INVALID_ARGUMENT; |
| } |
| Status status = ToAidlPacketType(packetHandle->getType(), &desc.type); |
| if (status != SUCCESS) { |
| return status; |
| } |
| desc.data = std::vector(reinterpret_cast<const signed char*>(packetHandle->getData()), |
| reinterpret_cast<const signed char*>(packetHandle->getData() + packetHandle->getSize())); |
| desc.size = packetHandle->getSize(); |
| if (static_cast<int32_t>(desc.data.size()) != desc.size) { |
| LOG(ERROR) << "mismatch in char data size and reported size"; |
| return Status::INVALID_ARGUMENT; |
| } |
| desc.sourceTimeStampMillis = packetHandle->getTimeStamp(); |
| desc.bufId = 0; |
| ScopedAStatus ret = mPacketHandlers[streamId]->deliverPacket(desc); |
| if (!ret.isOk()) { |
| LOG(ERROR) << "Dropping Semantic packet due to error "; |
| } |
| return Status::SUCCESS; |
| } |
| |
| Status AidlClientImpl::DispatchPixelData(int32_t streamId, |
| const std::shared_ptr<MemHandle>& packetHandle) { |
| PacketDescriptor desc; |
| |
| if (mPacketHandlers.find(streamId) == mPacketHandlers.end()) { |
| LOG(ERROR) << "Bad stream id"; |
| return Status::INVALID_ARGUMENT; |
| } |
| Status status = ToAidlPacketType(packetHandle->getType(), &desc.type); |
| if (status != Status::SUCCESS) { |
| LOG(ERROR) << "Invalid packet type"; |
| return status; |
| } |
| |
| // Copies the native handle to the aidl interface. |
| const native_handle_t* nativeHandle = |
| AHardwareBuffer_getNativeHandle(packetHandle->getHardwareBuffer()); |
| for (int i = 0; i < nativeHandle->numFds; i++) { |
| desc.handle.handle.fds.push_back(ndk::ScopedFileDescriptor(nativeHandle->data[i])); |
| } |
| for (int i = 0; i < nativeHandle->numInts; i++) { |
| desc.handle.handle.ints.push_back(nativeHandle->data[i + nativeHandle->numFds]); |
| } |
| |
| // Copies buffer descriptor to the aidl interface. |
| AHardwareBuffer_Desc bufferDesc; |
| AHardwareBuffer_describe(packetHandle->getHardwareBuffer(), &bufferDesc); |
| desc.handle.description.width = bufferDesc.width; |
| desc.handle.description.height = bufferDesc.height; |
| desc.handle.description.stride = bufferDesc.stride; |
| desc.handle.description.layers = bufferDesc.layers; |
| desc.handle.description.format = |
| static_cast<::aidl::android::hardware::graphics::common::PixelFormat>(bufferDesc.format); |
| desc.handle.description.usage = |
| static_cast<::aidl::android::hardware::graphics::common::BufferUsage>(bufferDesc.usage); |
| |
| desc.bufId = packetHandle->getBufferId(); |
| desc.sourceTimeStampMillis = packetHandle->getTimeStamp(); |
| |
| ScopedAStatus ret = mPacketHandlers[streamId]->deliverPacket(desc); |
| if (!ret.isOk()) { |
| LOG(ERROR) << "Unable to deliver packet. Dropping it and returning an error"; |
| return Status::INTERNAL_ERROR; |
| } |
| return Status::SUCCESS; |
| } |
| |
| // Thread-safe function to deliver new packets to client. |
| Status AidlClientImpl::dispatchPacketToClient(int32_t streamId, |
| const std::shared_ptr<MemHandle>& packetHandle) { |
| // TODO(146464279) implement. |
| if (!packetHandle) { |
| LOG(ERROR) << "invalid packetHandle"; |
| return Status::INVALID_ARGUMENT; |
| } |
| proto::PacketType packetType = packetHandle->getType(); |
| switch (packetType) { |
| case proto::SEMANTIC_DATA: |
| return DispatchSemanticData(streamId, packetHandle); |
| case proto::PIXEL_DATA: |
| return DispatchPixelData(streamId, packetHandle); |
| default: |
| LOG(ERROR) << "Unsupported packet type " << packetHandle->getType(); |
| return Status::INVALID_ARGUMENT; |
| } |
| return Status::SUCCESS; |
| } |
| |
| void AidlClientImpl::setPipeDebugger( |
| const std::shared_ptr<aidl::android::automotive::computepipe::runner::IPipeDebugger>& |
| pipeDebugger) { |
| mPipeDebugger = pipeDebugger; |
| } |
| |
| Status AidlClientImpl::stateUpdateNotification(const GraphState newState) { |
| if (mClientStateChangeCallback) { |
| (void)mClientStateChangeCallback->handleState(ToAidlState(newState)); |
| } |
| return Status::SUCCESS; |
| } |
| |
| ScopedAStatus AidlClientImpl::getPipeDescriptor(PipeDescriptor* _aidl_return) { |
| if (_aidl_return == nullptr) { |
| return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); |
| } |
| *_aidl_return = OptionsToPipeDescriptor(mGraphOptions); |
| return ScopedAStatus::ok(); |
| } |
| |
| ScopedAStatus AidlClientImpl::setPipeInputSource(int32_t configId) { |
| if (!isClientInitDone()) { |
| return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); |
| } |
| |
| proto::ConfigurationCommand configurationCommand; |
| configurationCommand.mutable_set_input_source()->set_source_id(configId); |
| |
| Status status = mEngine->processClientConfigUpdate(configurationCommand); |
| return ToNdkStatus(status); |
| } |
| |
| ScopedAStatus AidlClientImpl::setPipeOffloadOptions(int32_t configId) { |
| if (!isClientInitDone()) { |
| return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); |
| } |
| |
| proto::ConfigurationCommand configurationCommand; |
| configurationCommand.mutable_set_offload_offload()->set_offload_option_id(configId); |
| |
| Status status = mEngine->processClientConfigUpdate(configurationCommand); |
| return ToNdkStatus(status); |
| } |
| |
| ScopedAStatus AidlClientImpl::setPipeTermination(int32_t configId) { |
| if (!isClientInitDone()) { |
| return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); |
| } |
| |
| proto::ConfigurationCommand configurationCommand; |
| configurationCommand.mutable_set_termination_option()->set_termination_option_id(configId); |
| |
| Status status = mEngine->processClientConfigUpdate(configurationCommand); |
| return ToNdkStatus(status); |
| } |
| |
| ScopedAStatus AidlClientImpl::init(const std::shared_ptr<IPipeStateCallback>& stateCb) { |
| if (isClientInitDone()) { |
| return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); |
| } |
| |
| AIBinder_DeathRecipient* recipient = AIBinder_DeathRecipient_new(&deathNotifier); |
| AIBinder_linkToDeath(stateCb->asBinder().get(), recipient, this); |
| |
| mClientStateChangeCallback = stateCb; |
| return ScopedAStatus::ok(); |
| } |
| |
| bool AidlClientImpl::isClientInitDone() { |
| if (mClientStateChangeCallback == nullptr) { |
| return false; |
| } |
| return true; |
| } |
| |
| void AidlClientImpl::clientDied() { |
| LOG(INFO) << "Client has died"; |
| releaseRunner(); |
| } |
| |
| ScopedAStatus AidlClientImpl::setPipeOutputConfig(int32_t streamId, int32_t maxInFlightCount, |
| const std::shared_ptr<IPipeStream>& handler) { |
| if (!isClientInitDone()) { |
| return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); |
| } |
| |
| if (mPacketHandlers.find(streamId) != mPacketHandlers.end()) { |
| LOG(INFO) << "Handler for stream id " << streamId |
| << " has already" |
| " been registered."; |
| return ToNdkStatus(INVALID_ARGUMENT); |
| } |
| |
| mPacketHandlers.insert(std::pair<int, std::shared_ptr<IPipeStream>>(streamId, handler)); |
| |
| proto::ConfigurationCommand configurationCommand; |
| configurationCommand.mutable_set_output_stream()->set_stream_id(streamId); |
| configurationCommand.mutable_set_output_stream()->set_max_inflight_packets_count( |
| maxInFlightCount); |
| Status status = mEngine->processClientConfigUpdate(configurationCommand); |
| |
| if (status != SUCCESS) { |
| LOG(INFO) << "Failed to register handler for stream id " << streamId; |
| mPacketHandlers.erase(streamId); |
| } |
| return ToNdkStatus(status); |
| } |
| |
| ScopedAStatus AidlClientImpl::applyPipeConfigs() { |
| if (!isClientInitDone()) { |
| return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); |
| } |
| |
| proto::ControlCommand controlCommand; |
| *controlCommand.mutable_apply_configs() = proto::ApplyConfigs(); |
| |
| Status status = mEngine->processClientCommand(controlCommand); |
| return ToNdkStatus(status); |
| } |
| |
| ScopedAStatus AidlClientImpl::resetPipeConfigs() { |
| if (!isClientInitDone()) { |
| return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); |
| } |
| |
| proto::ControlCommand controlCommand; |
| *controlCommand.mutable_reset_configs() = proto::ResetConfigs(); |
| |
| Status status = mEngine->processClientCommand(controlCommand); |
| return ToNdkStatus(status); |
| } |
| |
| ScopedAStatus AidlClientImpl::startPipe() { |
| proto::ControlCommand controlCommand; |
| *controlCommand.mutable_start_graph() = proto::StartGraph(); |
| |
| Status status = mEngine->processClientCommand(controlCommand); |
| return ToNdkStatus(status); |
| } |
| |
| ScopedAStatus AidlClientImpl::stopPipe() { |
| proto::ControlCommand controlCommand; |
| *controlCommand.mutable_stop_graph() = proto::StopGraph(); |
| |
| Status status = mEngine->processClientCommand(controlCommand); |
| return ToNdkStatus(status); |
| } |
| |
| ScopedAStatus AidlClientImpl::doneWithPacket(int32_t bufferId, int32_t streamId) { |
| auto it = mPacketHandlers.find(streamId); |
| if (it == mPacketHandlers.end()) { |
| LOG(ERROR) << "Bad stream id provided for doneWithPacket call"; |
| return ToNdkStatus(Status::INVALID_ARGUMENT); |
| } |
| |
| return ToNdkStatus(mEngine->freePacket(bufferId, streamId)); |
| } |
| |
| ScopedAStatus AidlClientImpl::getPipeDebugger( |
| std::shared_ptr<aidl::android::automotive::computepipe::runner::IPipeDebugger>* |
| _aidl_return) { |
| if (_aidl_return == nullptr) { |
| return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); |
| } |
| if (mPipeDebugger == nullptr) { |
| return ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED); |
| } |
| *_aidl_return = mPipeDebugger; |
| return ScopedAStatus::ok(); |
| } |
| |
| ScopedAStatus AidlClientImpl::releaseRunner() { |
| proto::ControlCommand controlCommand; |
| *controlCommand.mutable_death_notification() = proto::DeathNotification(); |
| |
| Status status = mEngine->processClientCommand(controlCommand); |
| |
| mClientStateChangeCallback = nullptr; |
| mPacketHandlers.clear(); |
| return ToNdkStatus(status); |
| } |
| |
| } // namespace aidl_client |
| } // namespace client_interface |
| } // namespace runner |
| } // namespace computepipe |
| } // namespace automotive |
| } // namespace android |