// 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 #include "OutputConfig.pb.h" #include "PacketDescriptor.pb.h" #include "PipeOptionsConverter.h" #include "StatusUtil.h" #include #include #include #include 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(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& 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(packetHandle->getData()), reinterpret_cast(packetHandle->getData() + packetHandle->getSize())); desc.size = packetHandle->getSize(); if (static_cast(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& 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& 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& 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& 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& 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>(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_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