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