| /* |
| * Copyright 2016 The Chromium OS Authors. All rights reserved. |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "hal_adapter/arc_camera3_mojo_utils.h" |
| |
| #include <utility> |
| |
| #include <mojo/edk/embedder/embedder.h> |
| #include <mojo/edk/embedder/scoped_platform_handle.h> |
| #include <mojo/edk/system/handle_signals_state.h> |
| |
| namespace internal { |
| |
| mojo::ScopedHandle WrapPlatformHandle(int handle) { |
| MojoHandle wrapped_handle; |
| MojoResult wrap_result = mojo::edk::CreatePlatformHandleWrapper( |
| mojo::edk::ScopedPlatformHandle(mojo::edk::PlatformHandle(handle)), |
| &wrapped_handle); |
| if (wrap_result != MOJO_RESULT_OK) { |
| LOG(ERROR) << "Failed to wrap platform handle: " << wrap_result; |
| return mojo::ScopedHandle(mojo::Handle()); |
| } |
| return mojo::ScopedHandle(mojo::Handle(wrapped_handle)); |
| } |
| |
| // Transfers ownership of the handle. |
| int UnwrapPlatformHandle(mojo::ScopedHandle handle) { |
| mojo::edk::ScopedPlatformHandle scoped_platform_handle; |
| MojoResult mojo_result = mojo::edk::PassWrappedPlatformHandle( |
| handle.release().value(), &scoped_platform_handle); |
| if (mojo_result != MOJO_RESULT_OK) { |
| LOG(ERROR) << "Failed to unwrap handle: " << mojo_result; |
| return -EINVAL; |
| } |
| return scoped_platform_handle.release().handle; |
| } |
| |
| arc::mojom::HandlePtr SerializeHandle(int handle) { |
| arc::mojom::HandlePtr ret = arc::mojom::Handle::New(); |
| if (handle == -1) { |
| ret->set_none(true); |
| } else if (handle >= 0) { |
| ret->set_h(WrapPlatformHandle(handle)); |
| } else { |
| LOG(ERROR) << "Invalid handle to wrap"; |
| // Simply return an invalid handle to indicate that an error has occurred. |
| ret->set_h(mojo::ScopedHandle(mojo::Handle())); |
| } |
| return ret; |
| } |
| |
| // Transfers ownership of the handle. |
| int DeserializeHandle(const arc::mojom::HandlePtr& handle) { |
| if (handle->is_none()) { |
| return -1; |
| } |
| return UnwrapPlatformHandle(std::move(handle->get_h())); |
| } |
| |
| arc::mojom::NativeHandlePtr SerializeNativeHandle( |
| const native_handle_t* handle) { |
| arc::mojom::NativeHandlePtr ret = arc::mojom::NativeHandle::New(); |
| ret->version = handle->version; |
| ret->num_fds = handle->numFds; |
| ret->num_ints = handle->numInts; |
| |
| for (int i = 0; i < handle->numFds; i++) { |
| arc::mojom::HandlePtr wrapped_handle = SerializeHandle(handle->data[i]); |
| if (wrapped_handle->is_h() && !wrapped_handle->get_h().is_valid()) { |
| LOG(ERROR) << "Failed to wrap buffer handle"; |
| ret.reset(); |
| return ret; |
| } |
| ret->fds.push_back(std::move(wrapped_handle)); |
| } |
| |
| for (int i = 0; i < handle->numInts; i++) { |
| ret->ints.push_back(handle->data[handle->numFds + i]); |
| } |
| |
| return ret; |
| } |
| |
| // The caller must allocate the memory for out_handle. |
| int DeserializeNativeHandle(const arc::mojom::NativeHandlePtr& ptr, |
| native_handle_t* out_handle) { |
| out_handle->version = ptr->version; |
| out_handle->numFds = ptr->num_fds; |
| out_handle->numInts = ptr->num_ints; |
| for (int i = 0; i < ptr->num_fds; i++) { |
| int unwrapped_handle = DeserializeHandle(ptr->fds[i]); |
| if (unwrapped_handle == -EINVAL) { |
| LOG(ERROR) << "Failed to get native fd"; |
| for (int j = 0; j < i; j++) { |
| close(out_handle->data[j]); |
| } |
| return -EINVAL; |
| } |
| out_handle->data[i] = unwrapped_handle; |
| } |
| for (int i = 0; i < ptr->num_ints; i++) { |
| out_handle->data[ptr->num_fds + i] = ptr->ints[i]; |
| } |
| return 0; |
| } |
| |
| arc::mojom::Camera3StreamBufferPtr SerializeStreamBuffer( |
| const camera3_stream_buffer_t* buffer, |
| const UniqueStreams& streams) { |
| arc::mojom::Camera3StreamBufferPtr ret = |
| arc::mojom::Camera3StreamBuffer::New(); |
| |
| if (!buffer) { |
| ret.reset(); |
| return ret; |
| } |
| |
| auto it = streams.begin(); |
| for (; it != streams.end(); it++) { |
| if (it->second.get() == buffer->stream) { |
| break; |
| } |
| } |
| if (it == streams.end()) { |
| LOG(ERROR) << "Unknown stream set in buffer"; |
| ret.reset(); |
| return ret; |
| } |
| ret->stream_id = it->first; |
| |
| ret->buffer = SerializeNativeHandle(*buffer->buffer); |
| if (ret->buffer.is_null()) { |
| ret.reset(); |
| return ret; |
| } |
| |
| ret->status = buffer->status; |
| |
| ret->acquire_fence = SerializeHandle(buffer->acquire_fence); |
| if (ret->acquire_fence->is_h() && !ret->acquire_fence->get_h().is_valid()) { |
| LOG(ERROR) << "Failed to wrap acquire_fence"; |
| ret.reset(); |
| return ret; |
| } |
| |
| ret->release_fence = SerializeHandle(buffer->release_fence); |
| if (ret->release_fence->is_h() && !ret->release_fence->get_h().is_valid()) { |
| LOG(ERROR) << "Failed to wrap release_fence"; |
| ret.reset(); |
| return ret; |
| } |
| |
| return ret; |
| } |
| |
| int DeserializeStreamBuffer(const arc::mojom::Camera3StreamBufferPtr& ptr, |
| const UniqueStreams& streams, |
| camera3_stream_buffer_t* out_buffer) { |
| auto it = streams.find(ptr->stream_id); |
| if (it == streams.end()) { |
| LOG(ERROR) << "Unknown stream: " << ptr->stream_id; |
| return -EINVAL; |
| } |
| out_buffer->stream = it->second.get(); |
| |
| int ret = DeserializeNativeHandle( |
| ptr->buffer, *const_cast<native_handle**>(out_buffer->buffer)); |
| if (ret) { |
| return ret; |
| } |
| out_buffer->status = ptr->status; |
| |
| int unwrapped_handle; |
| unwrapped_handle = DeserializeHandle(ptr->acquire_fence); |
| if (unwrapped_handle == -EINVAL) { |
| LOG(ERROR) << "Failed to get acquire_fence"; |
| native_handle_close(*(out_buffer->buffer)); |
| return -EINVAL; |
| } |
| out_buffer->acquire_fence = unwrapped_handle; |
| |
| unwrapped_handle = DeserializeHandle(ptr->release_fence); |
| if (unwrapped_handle == -EINVAL) { |
| LOG(ERROR) << "Failed to get release_fence"; |
| native_handle_close(*(out_buffer->buffer)); |
| close(out_buffer->acquire_fence); |
| return -EINVAL; |
| } |
| out_buffer->release_fence = unwrapped_handle; |
| |
| return 0; |
| } |
| |
| int32_t SerializeCameraMetadata( |
| mojo::ScopedDataPipeProducerHandle* producer_handle, |
| mojo::ScopedDataPipeConsumerHandle* consumer_handle, |
| const camera_metadata_t* metadata) { |
| if (!metadata) { |
| return -EINVAL; |
| } |
| // Serialize camera metadata. |
| uint32_t data_size = get_camera_metadata_size(metadata); |
| VLOG(2) << "Camera metadata size: " << data_size; |
| struct MojoCreateDataPipeOptions options = { |
| sizeof(struct MojoCreateDataPipeOptions), |
| MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, 1, data_size}; |
| mojo::CreateDataPipe(&options, producer_handle, consumer_handle); |
| mojo::WriteDataRaw(producer_handle->get(), metadata, &data_size, |
| MOJO_WRITE_DATA_FLAG_ALL_OR_NONE); |
| if (!data_size) { |
| LOG(ERROR) << "Failed to write camera metadata through data pipe"; |
| return -EIO; |
| } |
| VLOG(2) << "Data written to pipe: " << data_size; |
| return 0; |
| } |
| |
| CameraMetadataUniquePtr DeserializeCameraMetadata( |
| mojo::DataPipeConsumerHandle consumer_handle) { |
| uint32_t data_size = 0; |
| mojo::edk::HandleSignalsState state; |
| MojoWait(consumer_handle.value(), MOJO_HANDLE_SIGNAL_READABLE, |
| MOJO_DEADLINE_INDEFINITE, &state); |
| DCHECK(MOJO_HANDLE_SIGNAL_READABLE == state.satisfied_signals); |
| |
| mojo::ReadDataRaw(consumer_handle, nullptr, &data_size, |
| MOJO_READ_DATA_FLAG_QUERY); |
| VLOG(2) << "Data size in pipe: " << data_size; |
| |
| camera_metadata_t* metadata = |
| reinterpret_cast<camera_metadata_t*>(new uint8_t[data_size]); |
| mojo::ReadDataRaw(consumer_handle, metadata, &data_size, |
| MOJO_READ_DATA_FLAG_ALL_OR_NONE); |
| if (!data_size) { |
| LOG(ERROR) << "Failed to read camera metadata from data pipe"; |
| // Simply return an invalid pointer to indicate that an error has occurred. |
| return CameraMetadataUniquePtr(); |
| } |
| VLOG(2) << "Metadata size=" << get_camera_metadata_size(metadata); |
| return CameraMetadataUniquePtr(metadata); |
| } |
| |
| base::Callback<void()> GetFutureCallback(Future<void>* future) { |
| return base::Bind(&Future<void>::Set, base::Unretained(future)); |
| } |
| |
| } // namespace internal |