1 // Copyright (C) 2019 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.c
14
15 #include "AidlClientImpl.h"
16
17 #include <vector>
18
19 #include "OutputConfig.pb.h"
20 #include "PacketDescriptor.pb.h"
21 #include "PipeOptionsConverter.h"
22 #include "StatusUtil.h"
23
24 #include <aidl/android/automotive/computepipe/runner/PacketDescriptor.h>
25 #include <aidl/android/automotive/computepipe/runner/PacketDescriptorPacketType.h>
26 #include <android-base/logging.h>
27 #include <android/binder_auto_utils.h>
28
29 namespace android {
30 namespace automotive {
31 namespace computepipe {
32 namespace runner {
33 namespace client_interface {
34 namespace aidl_client {
35 namespace {
36
37 using ::aidl::android::automotive::computepipe::runner::IPipeStateCallback;
38 using ::aidl::android::automotive::computepipe::runner::IPipeStream;
39 using ::aidl::android::automotive::computepipe::runner::PacketDescriptor;
40 using ::aidl::android::automotive::computepipe::runner::PacketDescriptorPacketType;
41 using ::aidl::android::automotive::computepipe::runner::PipeDescriptor;
42 using ::aidl::android::automotive::computepipe::runner::PipeState;
43 using ::ndk::ScopedAStatus;
44
ToAidlState(GraphState state)45 PipeState ToAidlState(GraphState state) {
46 switch (state) {
47 case RESET:
48 return PipeState::RESET;
49 case CONFIG_DONE:
50 return PipeState::CONFIG_DONE;
51 case RUNNING:
52 return PipeState::RUNNING;
53 case DONE:
54 return PipeState::DONE;
55 case ERR_HALT:
56 default:
57 return PipeState::ERR_HALT;
58 }
59 }
60
deathNotifier(void * cookie)61 void deathNotifier(void* cookie) {
62 CHECK(cookie);
63 AidlClientImpl* iface = static_cast<AidlClientImpl*>(cookie);
64 iface->clientDied();
65 }
66
ToAidlPacketType(proto::PacketType type,PacketDescriptorPacketType * outType)67 Status ToAidlPacketType(proto::PacketType type, PacketDescriptorPacketType* outType) {
68 if (outType == nullptr) {
69 return Status::INTERNAL_ERROR;
70 }
71 switch (type) {
72 case proto::SEMANTIC_DATA:
73 *outType = PacketDescriptorPacketType::SEMANTIC_DATA;
74 return Status::SUCCESS;
75 case proto::PIXEL_DATA:
76 *outType = PacketDescriptorPacketType::PIXEL_DATA;
77 return Status::SUCCESS;
78 default:
79 LOG(ERROR) << "unknown packet type " << type;
80 return Status::INVALID_ARGUMENT;
81 }
82 }
83
84 } // namespace
85
DispatchSemanticData(int32_t streamId,const std::shared_ptr<MemHandle> & packetHandle)86 Status AidlClientImpl::DispatchSemanticData(int32_t streamId,
87 const std::shared_ptr<MemHandle>& packetHandle) {
88 PacketDescriptor desc;
89
90 if (mPacketHandlers.find(streamId) == mPacketHandlers.end()) {
91 LOG(ERROR) << "Bad streamId";
92 return Status::INVALID_ARGUMENT;
93 }
94 Status status = ToAidlPacketType(packetHandle->getType(), &desc.type);
95 if (status != SUCCESS) {
96 return status;
97 }
98 desc.data = std::vector(reinterpret_cast<const signed char*>(packetHandle->getData()),
99 reinterpret_cast<const signed char*>(packetHandle->getData() + packetHandle->getSize()));
100 desc.size = packetHandle->getSize();
101 if (static_cast<int32_t>(desc.data.size()) != desc.size) {
102 LOG(ERROR) << "mismatch in char data size and reported size";
103 return Status::INVALID_ARGUMENT;
104 }
105 desc.sourceTimeStampMillis = packetHandle->getTimeStamp();
106 desc.bufId = 0;
107 ScopedAStatus ret = mPacketHandlers[streamId]->deliverPacket(desc);
108 if (!ret.isOk()) {
109 LOG(ERROR) << "Dropping Semantic packet due to error ";
110 }
111 return Status::SUCCESS;
112 }
113
DispatchPixelData(int32_t streamId,const std::shared_ptr<MemHandle> & packetHandle)114 Status AidlClientImpl::DispatchPixelData(int32_t streamId,
115 const std::shared_ptr<MemHandle>& packetHandle) {
116 PacketDescriptor desc;
117
118 if (mPacketHandlers.find(streamId) == mPacketHandlers.end()) {
119 LOG(ERROR) << "Bad stream id";
120 return Status::INVALID_ARGUMENT;
121 }
122 Status status = ToAidlPacketType(packetHandle->getType(), &desc.type);
123 if (status != Status::SUCCESS) {
124 LOG(ERROR) << "Invalid packet type";
125 return status;
126 }
127
128 // Copies the native handle to the aidl interface.
129 const native_handle_t* nativeHandle =
130 AHardwareBuffer_getNativeHandle(packetHandle->getHardwareBuffer());
131 for (int i = 0; i < nativeHandle->numFds; i++) {
132 desc.handle.handle.fds.push_back(ndk::ScopedFileDescriptor(nativeHandle->data[i]));
133 }
134 for (int i = 0; i < nativeHandle->numInts; i++) {
135 desc.handle.handle.ints.push_back(nativeHandle->data[i + nativeHandle->numFds]);
136 }
137
138 // Copies buffer descriptor to the aidl interface.
139 AHardwareBuffer_Desc bufferDesc;
140 AHardwareBuffer_describe(packetHandle->getHardwareBuffer(), &bufferDesc);
141 desc.handle.description.width = bufferDesc.width;
142 desc.handle.description.height = bufferDesc.height;
143 desc.handle.description.stride = bufferDesc.stride;
144 desc.handle.description.layers = bufferDesc.layers;
145 desc.handle.description.format =
146 static_cast<::aidl::android::hardware::graphics::common::PixelFormat>(bufferDesc.format);
147 desc.handle.description.usage =
148 static_cast<::aidl::android::hardware::graphics::common::BufferUsage>(bufferDesc.usage);
149
150 desc.bufId = packetHandle->getBufferId();
151 desc.sourceTimeStampMillis = packetHandle->getTimeStamp();
152
153 ScopedAStatus ret = mPacketHandlers[streamId]->deliverPacket(desc);
154 if (!ret.isOk()) {
155 LOG(ERROR) << "Unable to deliver packet. Dropping it and returning an error";
156 return Status::INTERNAL_ERROR;
157 }
158 return Status::SUCCESS;
159 }
160
161 // Thread-safe function to deliver new packets to client.
dispatchPacketToClient(int32_t streamId,const std::shared_ptr<MemHandle> & packetHandle)162 Status AidlClientImpl::dispatchPacketToClient(int32_t streamId,
163 const std::shared_ptr<MemHandle>& packetHandle) {
164 // TODO(146464279) implement.
165 if (!packetHandle) {
166 LOG(ERROR) << "invalid packetHandle";
167 return Status::INVALID_ARGUMENT;
168 }
169 proto::PacketType packetType = packetHandle->getType();
170 switch (packetType) {
171 case proto::SEMANTIC_DATA:
172 return DispatchSemanticData(streamId, packetHandle);
173 case proto::PIXEL_DATA:
174 return DispatchPixelData(streamId, packetHandle);
175 default:
176 LOG(ERROR) << "Unsupported packet type " << packetHandle->getType();
177 return Status::INVALID_ARGUMENT;
178 }
179 return Status::SUCCESS;
180 }
181
setPipeDebugger(const std::shared_ptr<aidl::android::automotive::computepipe::runner::IPipeDebugger> & pipeDebugger)182 void AidlClientImpl::setPipeDebugger(
183 const std::shared_ptr<aidl::android::automotive::computepipe::runner::IPipeDebugger>&
184 pipeDebugger) {
185 mPipeDebugger = pipeDebugger;
186 }
187
stateUpdateNotification(const GraphState newState)188 Status AidlClientImpl::stateUpdateNotification(const GraphState newState) {
189 if (mClientStateChangeCallback) {
190 (void)mClientStateChangeCallback->handleState(ToAidlState(newState));
191 }
192 return Status::SUCCESS;
193 }
194
getPipeDescriptor(PipeDescriptor * _aidl_return)195 ScopedAStatus AidlClientImpl::getPipeDescriptor(PipeDescriptor* _aidl_return) {
196 if (_aidl_return == nullptr) {
197 return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
198 }
199 *_aidl_return = OptionsToPipeDescriptor(mGraphOptions);
200 return ScopedAStatus::ok();
201 }
202
setPipeInputSource(int32_t configId)203 ScopedAStatus AidlClientImpl::setPipeInputSource(int32_t configId) {
204 if (!isClientInitDone()) {
205 return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
206 }
207
208 proto::ConfigurationCommand configurationCommand;
209 configurationCommand.mutable_set_input_source()->set_source_id(configId);
210
211 Status status = mEngine->processClientConfigUpdate(configurationCommand);
212 return ToNdkStatus(status);
213 }
214
setPipeOffloadOptions(int32_t configId)215 ScopedAStatus AidlClientImpl::setPipeOffloadOptions(int32_t configId) {
216 if (!isClientInitDone()) {
217 return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
218 }
219
220 proto::ConfigurationCommand configurationCommand;
221 configurationCommand.mutable_set_offload_offload()->set_offload_option_id(configId);
222
223 Status status = mEngine->processClientConfigUpdate(configurationCommand);
224 return ToNdkStatus(status);
225 }
226
setPipeTermination(int32_t configId)227 ScopedAStatus AidlClientImpl::setPipeTermination(int32_t configId) {
228 if (!isClientInitDone()) {
229 return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
230 }
231
232 proto::ConfigurationCommand configurationCommand;
233 configurationCommand.mutable_set_termination_option()->set_termination_option_id(configId);
234
235 Status status = mEngine->processClientConfigUpdate(configurationCommand);
236 return ToNdkStatus(status);
237 }
238
init(const std::shared_ptr<IPipeStateCallback> & stateCb)239 ScopedAStatus AidlClientImpl::init(const std::shared_ptr<IPipeStateCallback>& stateCb) {
240 if (isClientInitDone()) {
241 return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
242 }
243
244 AIBinder_DeathRecipient* recipient = AIBinder_DeathRecipient_new(&deathNotifier);
245 AIBinder_linkToDeath(stateCb->asBinder().get(), recipient, this);
246
247 mClientStateChangeCallback = stateCb;
248 return ScopedAStatus::ok();
249 }
250
isClientInitDone()251 bool AidlClientImpl::isClientInitDone() {
252 if (mClientStateChangeCallback == nullptr) {
253 return false;
254 }
255 return true;
256 }
257
clientDied()258 void AidlClientImpl::clientDied() {
259 LOG(INFO) << "Client has died";
260 releaseRunner();
261 }
262
setPipeOutputConfig(int32_t streamId,int32_t maxInFlightCount,const std::shared_ptr<IPipeStream> & handler)263 ScopedAStatus AidlClientImpl::setPipeOutputConfig(int32_t streamId, int32_t maxInFlightCount,
264 const std::shared_ptr<IPipeStream>& handler) {
265 if (!isClientInitDone()) {
266 return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
267 }
268
269 if (mPacketHandlers.find(streamId) != mPacketHandlers.end()) {
270 LOG(INFO) << "Handler for stream id " << streamId
271 << " has already"
272 " been registered.";
273 return ToNdkStatus(INVALID_ARGUMENT);
274 }
275
276 mPacketHandlers.insert(std::pair<int, std::shared_ptr<IPipeStream>>(streamId, handler));
277
278 proto::ConfigurationCommand configurationCommand;
279 configurationCommand.mutable_set_output_stream()->set_stream_id(streamId);
280 configurationCommand.mutable_set_output_stream()->set_max_inflight_packets_count(
281 maxInFlightCount);
282 Status status = mEngine->processClientConfigUpdate(configurationCommand);
283
284 if (status != SUCCESS) {
285 LOG(INFO) << "Failed to register handler for stream id " << streamId;
286 mPacketHandlers.erase(streamId);
287 }
288 return ToNdkStatus(status);
289 }
290
applyPipeConfigs()291 ScopedAStatus AidlClientImpl::applyPipeConfigs() {
292 if (!isClientInitDone()) {
293 return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
294 }
295
296 proto::ControlCommand controlCommand;
297 *controlCommand.mutable_apply_configs() = proto::ApplyConfigs();
298
299 Status status = mEngine->processClientCommand(controlCommand);
300 return ToNdkStatus(status);
301 }
302
resetPipeConfigs()303 ScopedAStatus AidlClientImpl::resetPipeConfigs() {
304 if (!isClientInitDone()) {
305 return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
306 }
307
308 proto::ControlCommand controlCommand;
309 *controlCommand.mutable_reset_configs() = proto::ResetConfigs();
310
311 Status status = mEngine->processClientCommand(controlCommand);
312 return ToNdkStatus(status);
313 }
314
startPipe()315 ScopedAStatus AidlClientImpl::startPipe() {
316 proto::ControlCommand controlCommand;
317 *controlCommand.mutable_start_graph() = proto::StartGraph();
318
319 Status status = mEngine->processClientCommand(controlCommand);
320 return ToNdkStatus(status);
321 }
322
stopPipe()323 ScopedAStatus AidlClientImpl::stopPipe() {
324 proto::ControlCommand controlCommand;
325 *controlCommand.mutable_stop_graph() = proto::StopGraph();
326
327 Status status = mEngine->processClientCommand(controlCommand);
328 return ToNdkStatus(status);
329 }
330
doneWithPacket(int32_t bufferId,int32_t streamId)331 ScopedAStatus AidlClientImpl::doneWithPacket(int32_t bufferId, int32_t streamId) {
332 auto it = mPacketHandlers.find(streamId);
333 if (it == mPacketHandlers.end()) {
334 LOG(ERROR) << "Bad stream id provided for doneWithPacket call";
335 return ToNdkStatus(Status::INVALID_ARGUMENT);
336 }
337
338 return ToNdkStatus(mEngine->freePacket(bufferId, streamId));
339 }
340
getPipeDebugger(std::shared_ptr<aidl::android::automotive::computepipe::runner::IPipeDebugger> * _aidl_return)341 ScopedAStatus AidlClientImpl::getPipeDebugger(
342 std::shared_ptr<aidl::android::automotive::computepipe::runner::IPipeDebugger>*
343 _aidl_return) {
344 if (_aidl_return == nullptr) {
345 return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
346 }
347 if (mPipeDebugger == nullptr) {
348 return ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
349 }
350 *_aidl_return = mPipeDebugger;
351 return ScopedAStatus::ok();
352 }
353
releaseRunner()354 ScopedAStatus AidlClientImpl::releaseRunner() {
355 proto::ControlCommand controlCommand;
356 *controlCommand.mutable_death_notification() = proto::DeathNotification();
357
358 Status status = mEngine->processClientCommand(controlCommand);
359
360 mClientStateChangeCallback = nullptr;
361 mPacketHandlers.clear();
362 return ToNdkStatus(status);
363 }
364
365 } // namespace aidl_client
366 } // namespace client_interface
367 } // namespace runner
368 } // namespace computepipe
369 } // namespace automotive
370 } // namespace android
371