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 uint8_t*>(packetHandle->getData()),
99 reinterpret_cast<const uint8_t*>(packetHandle->getData() +
100 packetHandle->getSize()));
101 desc.size = packetHandle->getSize();
102 if (static_cast<int32_t>(desc.data.size()) != desc.size) {
103 LOG(ERROR) << "mismatch in char data size and reported size";
104 return Status::INVALID_ARGUMENT;
105 }
106 desc.sourceTimeStampMillis = packetHandle->getTimeStamp();
107 desc.bufId = 0;
108 ScopedAStatus ret = mPacketHandlers[streamId]->deliverPacket(desc);
109 if (!ret.isOk()) {
110 LOG(ERROR) << "Dropping Semantic packet due to error ";
111 }
112 return Status::SUCCESS;
113 }
114
DispatchPixelData(int32_t streamId,const std::shared_ptr<MemHandle> & packetHandle)115 Status AidlClientImpl::DispatchPixelData(int32_t streamId,
116 const std::shared_ptr<MemHandle>& packetHandle) {
117 PacketDescriptor desc;
118
119 if (mPacketHandlers.find(streamId) == mPacketHandlers.end()) {
120 LOG(ERROR) << "Bad stream id";
121 return Status::INVALID_ARGUMENT;
122 }
123 Status status = ToAidlPacketType(packetHandle->getType(), &desc.type);
124 if (status != Status::SUCCESS) {
125 LOG(ERROR) << "Invalid packet type";
126 return status;
127 }
128
129 // Copies the native handle to the aidl interface.
130 const native_handle_t* nativeHandle =
131 AHardwareBuffer_getNativeHandle(packetHandle->getHardwareBuffer());
132 for (int i = 0; i < nativeHandle->numFds; i++) {
133 desc.handle.handle.fds.push_back(ndk::ScopedFileDescriptor(nativeHandle->data[i]));
134 }
135 for (int i = 0; i < nativeHandle->numInts; i++) {
136 desc.handle.handle.ints.push_back(nativeHandle->data[i + nativeHandle->numFds]);
137 }
138
139 // Copies buffer descriptor to the aidl interface.
140 AHardwareBuffer_Desc bufferDesc;
141 AHardwareBuffer_describe(packetHandle->getHardwareBuffer(), &bufferDesc);
142 desc.handle.description.width = bufferDesc.width;
143 desc.handle.description.height = bufferDesc.height;
144 desc.handle.description.stride = bufferDesc.stride;
145 desc.handle.description.layers = bufferDesc.layers;
146 desc.handle.description.format =
147 static_cast<::aidl::android::hardware::graphics::common::PixelFormat>(bufferDesc.format);
148 desc.handle.description.usage =
149 static_cast<::aidl::android::hardware::graphics::common::BufferUsage>(bufferDesc.usage);
150
151 desc.bufId = packetHandle->getBufferId();
152 desc.sourceTimeStampMillis = packetHandle->getTimeStamp();
153
154 ScopedAStatus ret = mPacketHandlers[streamId]->deliverPacket(desc);
155 if (!ret.isOk()) {
156 LOG(ERROR) << "Unable to deliver packet. Dropping it and returning an error";
157 return Status::INTERNAL_ERROR;
158 }
159 return Status::SUCCESS;
160 }
161
162 // Thread-safe function to deliver new packets to client.
dispatchPacketToClient(int32_t streamId,const std::shared_ptr<MemHandle> & packetHandle)163 Status AidlClientImpl::dispatchPacketToClient(int32_t streamId,
164 const std::shared_ptr<MemHandle>& packetHandle) {
165 // TODO(146464279) implement.
166 if (!packetHandle) {
167 LOG(ERROR) << "invalid packetHandle";
168 return Status::INVALID_ARGUMENT;
169 }
170 proto::PacketType packetType = packetHandle->getType();
171 switch (packetType) {
172 case proto::SEMANTIC_DATA:
173 return DispatchSemanticData(streamId, packetHandle);
174 case proto::PIXEL_DATA:
175 return DispatchPixelData(streamId, packetHandle);
176 default:
177 LOG(ERROR) << "Unsupported packet type " << packetHandle->getType();
178 return Status::INVALID_ARGUMENT;
179 }
180 return Status::SUCCESS;
181 }
182
setPipeDebugger(const std::shared_ptr<aidl::android::automotive::computepipe::runner::IPipeDebugger> & pipeDebugger)183 void AidlClientImpl::setPipeDebugger(
184 const std::shared_ptr<aidl::android::automotive::computepipe::runner::IPipeDebugger>&
185 pipeDebugger) {
186 mPipeDebugger = pipeDebugger;
187 }
188
stateUpdateNotification(const GraphState newState)189 Status AidlClientImpl::stateUpdateNotification(const GraphState newState) {
190 if (mClientStateChangeCallback) {
191 (void)mClientStateChangeCallback->handleState(ToAidlState(newState));
192 }
193 return Status::SUCCESS;
194 }
195
getPipeDescriptor(PipeDescriptor * _aidl_return)196 ScopedAStatus AidlClientImpl::getPipeDescriptor(PipeDescriptor* _aidl_return) {
197 if (_aidl_return == nullptr) {
198 return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
199 }
200 *_aidl_return = OptionsToPipeDescriptor(mGraphOptions);
201 return ScopedAStatus::ok();
202 }
203
setPipeInputSource(int32_t configId)204 ScopedAStatus AidlClientImpl::setPipeInputSource(int32_t configId) {
205 if (!isClientInitDone()) {
206 return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
207 }
208
209 proto::ConfigurationCommand configurationCommand;
210 configurationCommand.mutable_set_input_source()->set_source_id(configId);
211
212 Status status = mEngine->processClientConfigUpdate(configurationCommand);
213 return ToNdkStatus(status);
214 }
215
setPipeOffloadOptions(int32_t configId)216 ScopedAStatus AidlClientImpl::setPipeOffloadOptions(int32_t configId) {
217 if (!isClientInitDone()) {
218 return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
219 }
220
221 proto::ConfigurationCommand configurationCommand;
222 configurationCommand.mutable_set_offload_offload()->set_offload_option_id(configId);
223
224 Status status = mEngine->processClientConfigUpdate(configurationCommand);
225 return ToNdkStatus(status);
226 }
227
setPipeTermination(int32_t configId)228 ScopedAStatus AidlClientImpl::setPipeTermination(int32_t configId) {
229 if (!isClientInitDone()) {
230 return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
231 }
232
233 proto::ConfigurationCommand configurationCommand;
234 configurationCommand.mutable_set_termination_option()->set_termination_option_id(configId);
235
236 Status status = mEngine->processClientConfigUpdate(configurationCommand);
237 return ToNdkStatus(status);
238 }
239
init(const std::shared_ptr<IPipeStateCallback> & stateCb)240 ScopedAStatus AidlClientImpl::init(const std::shared_ptr<IPipeStateCallback>& stateCb) {
241 if (isClientInitDone()) {
242 return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
243 }
244
245 AIBinder_DeathRecipient* recipient = AIBinder_DeathRecipient_new(&deathNotifier);
246 AIBinder_linkToDeath(stateCb->asBinder().get(), recipient, this);
247
248 mClientStateChangeCallback = stateCb;
249 return ScopedAStatus::ok();
250 }
251
isClientInitDone()252 bool AidlClientImpl::isClientInitDone() {
253 if (mClientStateChangeCallback == nullptr) {
254 return false;
255 }
256 return true;
257 }
258
clientDied()259 void AidlClientImpl::clientDied() {
260 LOG(INFO) << "Client has died";
261 releaseRunner();
262 }
263
setPipeOutputConfig(int32_t streamId,int32_t maxInFlightCount,const std::shared_ptr<IPipeStream> & handler)264 ScopedAStatus AidlClientImpl::setPipeOutputConfig(int32_t streamId, int32_t maxInFlightCount,
265 const std::shared_ptr<IPipeStream>& handler) {
266 if (!isClientInitDone()) {
267 return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
268 }
269
270 if (mPacketHandlers.find(streamId) != mPacketHandlers.end()) {
271 LOG(INFO) << "Handler for stream id " << streamId
272 << " has already"
273 " been registered.";
274 return ToNdkStatus(INVALID_ARGUMENT);
275 }
276
277 mPacketHandlers.insert(std::pair<int, std::shared_ptr<IPipeStream>>(streamId, handler));
278
279 proto::ConfigurationCommand configurationCommand;
280 configurationCommand.mutable_set_output_stream()->set_stream_id(streamId);
281 configurationCommand.mutable_set_output_stream()->set_max_inflight_packets_count(
282 maxInFlightCount);
283 Status status = mEngine->processClientConfigUpdate(configurationCommand);
284
285 if (status != SUCCESS) {
286 LOG(INFO) << "Failed to register handler for stream id " << streamId;
287 mPacketHandlers.erase(streamId);
288 }
289 return ToNdkStatus(status);
290 }
291
applyPipeConfigs()292 ScopedAStatus AidlClientImpl::applyPipeConfigs() {
293 if (!isClientInitDone()) {
294 return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
295 }
296
297 proto::ControlCommand controlCommand;
298 *controlCommand.mutable_apply_configs() = proto::ApplyConfigs();
299
300 Status status = mEngine->processClientCommand(controlCommand);
301 return ToNdkStatus(status);
302 }
303
resetPipeConfigs()304 ScopedAStatus AidlClientImpl::resetPipeConfigs() {
305 if (!isClientInitDone()) {
306 return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
307 }
308
309 proto::ControlCommand controlCommand;
310 *controlCommand.mutable_reset_configs() = proto::ResetConfigs();
311
312 Status status = mEngine->processClientCommand(controlCommand);
313 return ToNdkStatus(status);
314 }
315
startPipe()316 ScopedAStatus AidlClientImpl::startPipe() {
317 proto::ControlCommand controlCommand;
318 *controlCommand.mutable_start_graph() = proto::StartGraph();
319
320 Status status = mEngine->processClientCommand(controlCommand);
321 return ToNdkStatus(status);
322 }
323
stopPipe()324 ScopedAStatus AidlClientImpl::stopPipe() {
325 proto::ControlCommand controlCommand;
326 *controlCommand.mutable_stop_graph() = proto::StopGraph();
327
328 Status status = mEngine->processClientCommand(controlCommand);
329 return ToNdkStatus(status);
330 }
331
doneWithPacket(int32_t bufferId,int32_t streamId)332 ScopedAStatus AidlClientImpl::doneWithPacket(int32_t bufferId, int32_t streamId) {
333 auto it = mPacketHandlers.find(streamId);
334 if (it == mPacketHandlers.end()) {
335 LOG(ERROR) << "Bad stream id provided for doneWithPacket call";
336 return ToNdkStatus(Status::INVALID_ARGUMENT);
337 }
338
339 return ToNdkStatus(mEngine->freePacket(bufferId, streamId));
340 }
341
getPipeDebugger(std::shared_ptr<aidl::android::automotive::computepipe::runner::IPipeDebugger> * _aidl_return)342 ScopedAStatus AidlClientImpl::getPipeDebugger(
343 std::shared_ptr<aidl::android::automotive::computepipe::runner::IPipeDebugger>*
344 _aidl_return) {
345 if (_aidl_return == nullptr) {
346 return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
347 }
348 if (mPipeDebugger == nullptr) {
349 return ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
350 }
351 *_aidl_return = mPipeDebugger;
352 return ScopedAStatus::ok();
353 }
354
releaseRunner()355 ScopedAStatus AidlClientImpl::releaseRunner() {
356 proto::ControlCommand controlCommand;
357 *controlCommand.mutable_death_notification() = proto::DeathNotification();
358
359 Status status = mEngine->processClientCommand(controlCommand);
360
361 mClientStateChangeCallback = nullptr;
362 mPacketHandlers.clear();
363 return ToNdkStatus(status);
364 }
365
366 } // namespace aidl_client
367 } // namespace client_interface
368 } // namespace runner
369 } // namespace computepipe
370 } // namespace automotive
371 } // namespace android
372