372 lines
13 KiB
C++
372 lines
13 KiB
C++
// 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 uint8_t*>(packetHandle->getData()),
|
|
reinterpret_cast<const uint8_t*>(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
|