blob: 1a017c3cd5b3908b1fc3806af89db7796fe4cfea [file] [log] [blame] [edit]
/*
* Copyright (C) 2024 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.
*/
#include <fmq/AidlMessageQueue.h>
using aidl::android::hardware::common::NativeHandle;
using aidl::android::hardware::common::fmq::GrantorDescriptor;
using aidl::android::hardware::common::fmq::SynchronizedReadWrite;
using namespace android;
struct MemTransaction {
MessageQueueBase<AidlMQDescriptorShim, MQErased,
FlavorTypeToValue<SynchronizedReadWrite>::value>::MemRegion first;
MessageQueueBase<AidlMQDescriptorShim, MQErased,
FlavorTypeToValue<SynchronizedReadWrite>::value>::MemRegion second;
};
typedef MQDescriptor<MQErased, SynchronizedReadWrite> ErasedMessageQueueDesc;
GrantorDescriptor convertGrantor(int32_t fdIndex, int32_t offset, int64_t extent);
enum Error : int {
NONE,
POINTER_CORRUPTION, /** Read/write pointers mismatch */
};
/**
* Construct a C++ AIDL MQDescriptor<MQErased, SynchronizedReadWrite> (aka an
* ErasedMessageQueueDesc) from the fields of a Rust AIDL
* MQDescriptor<MQErased, SynchronizedReadWrite>.
*
* These two types are semantically equivalent but come from separate AIDL
* codegen backends, so we must convert between them. To convert in the opposite
* direction, use the descFoo methods to access each field, and manually build
* the Rust AIDL MQDescriptor<MQErased, SynchronizedReadWrite> instance;
* see the Rust MessageQueue<T>::dupe_desc method.
*
* @param grantors Pointer to the start of the MQDescriptor's GrantorDescriptor
* array.
* @param n_grantors The length of the MQDescriptor's GrantorDescriptor array.
* @param handle_fds Pointer to the start of the MQDescriptor's NativeHandle's
* file-descriptor array. Ownership of array and contents is not transferred.
* @param handle_n_fds The corresponding length.
* @param handle_ints Pointer to the start of the MQDescriptor's NativeHandle's
* integer array. Ownership of the array is not transferred.
* @param handle_n_ints The corresponding length.
* @param quantum The MQDescriptor's quantum.
* @param flags The MQDescriptor's flags.
*
* @return A heap-allocated ErasedMessageQueueDesc instance owned by the caller,
* which must be freed with freeDesc.
*/
ErasedMessageQueueDesc* convertDesc(const GrantorDescriptor* grantors, size_t n_grantors,
const int* handle_fds, size_t handle_n_fds,
const int32_t* handle_ints, size_t handle_n_ints,
int32_t quantum, int32_t flags);
/**
* Free a heap-allocated ErasedMessageQueueDesc. Simply calls delete.
*
* @param desc The ErasedMessageQueueDesc to free.
*/
void freeDesc(ErasedMessageQueueDesc* desc);
/**
* The following functions project out individual fields of an
* ErasedMessageQueueDesc as FFI-safe types to enable constructing a Rust AIDL
* MQDescriptor<MQErased, SynchronizedReadWrite> from a C++ AIDL one. See the
* Rust MessageQueue<T>::dupe_desc method.
*/
const GrantorDescriptor* descGrantors(const ErasedMessageQueueDesc& desc);
size_t descNumGrantors(const ErasedMessageQueueDesc& desc);
const ndk::ScopedFileDescriptor* descHandleFDs(const ErasedMessageQueueDesc& desc);
size_t descHandleNumFDs(const ErasedMessageQueueDesc& desc);
const int* descHandleInts(const ErasedMessageQueueDesc& desc);
size_t descHandleNumInts(const ErasedMessageQueueDesc& desc);
int32_t descQuantum(const ErasedMessageQueueDesc& desc);
int32_t descFlags(const ErasedMessageQueueDesc& desc);
/**
* ErasedMessageQueue is a monomorphized wrapper around AidlMessageQueue that lets
* us wrap it in an idiomatic Rust API. It does not statically know its element
* type, but treats elements as opaque objects whose size is given by the
* MQDescriptor.
*/
class ErasedMessageQueue {
/* This must be a unique_ptr because bindgen cannot handle by-value fields
* of template class type. */
std::unique_ptr<AidlMessageQueue<MQErased, SynchronizedReadWrite>> inner;
public:
ErasedMessageQueue(const ErasedMessageQueueDesc& desc, bool resetPointers = true);
ErasedMessageQueue(size_t numElementsInQueue, bool configureEventFlagWord, size_t quantum);
/**
* @param errorDetected Optional output parameter which indicates
* any errors that the client might care about.
* @param errorMessage Optional output parameter for a human-readable
* error description.
*
* @return Number of items of type T that can be written into the FMQ
* without a read.
*/
size_t availableToWrite(Error* errorDetected = nullptr) const;
/**
* @param errorDetected Optional output parameter which indicates
* any errors that the client might care about.
* @param errorMessage Optional output parameter for a human-readable
* error description.
*
* @return Number of items of type T that are waiting to be read from the
* FMQ.
*/
size_t availableToRead(Error* errorDetected = nullptr) const;
/**
* Get a MemTransaction object to write `nMessages` elements.
* Once the write is performed using the information from MemTransaction,
* the write operation is to be committed using a call to commitWrite().
*
* @param nMessages Number of messages of the element type.
* @param Pointer to MemTransaction struct that describes memory to write
* `nMessages` items of the element type. If a write of size `nMessages` is
* not possible, the base addresses in the `MemTransaction` object will be
* set to nullptr.
*
* @return Whether it is possible to write `nMessages` items into the FMQ.
*/
bool beginWrite(size_t nMessages, MemTransaction* memTx) const;
/**
* Commit a write of size `nMessages`. To be only used after a call to
* `beginWrite()`.
*
* @param nMessages number of messages of the element type to be written.
*
* @return Whether the write operation of size `nMessages` succeeded.
*/
bool commitWrite(size_t nMessages);
/**
* Perform a blocking write of `count` items into the FMQ using EventFlags.
* Does not support partial writes.
*
* The method will return false without blocking if any of the following
* conditions are true:
* - If the FMQ does not own an EventFlag object.
* - If `count` is greater than the FMQ size.
*
* @param data Pointer to the array of items of the element type.
* @param count Number of items in array.
* @param timeOutNanos Number of nanoseconds after which the blocking
* write attempt is aborted.
*
* @return Whether the write was successful.
*/
bool writeBlocking(const void* data, size_t count, int64_t timeOutNanos);
/**
* Get a MemTransaction object to read `nMessages` elements.
* Once the read is performed using the information from MemTransaction,
* the read operation is to be committed using a call to `commitRead()`.
*
* @param nMessages Number of messages of the element type.
* @param pointer to MemTransaction struct that describes memory to read
* `nMessages` items of the element type. If a read of size `nMessages` is
* not possible, the base pointers in the `MemTransaction` object returned
* will be set to nullptr.
*
* @return bool Whether it is possible to read `nMessages` items from the
* FMQ.
*/
bool beginRead(size_t nMessages, MemTransaction* memTx) const;
/**
* Commit a read of size `nMessages`. To be only used after a call to
* `beginRead()`.
*
* @param nMessages number of messages of the element type to be read.
*
* @return bool Whether the read operation of size `nMessages` succeeded.
*/
bool commitRead(size_t nMessages);
/**
* Perform a blocking read operation of `count` items from the FMQ. Does not
* perform a partial read.
*
* The method will return false without blocking if any of the following
* conditions are true:
* -If the FMQ does not own an EventFlag object.
* -If `count` is greater than the FMQ size.
*
* @param data Pointer to the array to which read data is to be written.
* @param count Number of items to be read.
* @param timeOutNanos Number of nanoseconds after which the blocking
* read attempt is aborted.
*
* @return Whether the read was successful.
*/
bool readBlocking(void* data, size_t count, int64_t timeOutNanos);
/**
* Get a pointer to the EventFlag word if the FMQ has one.
*
* @return Pointer to an EventFlag word, or nullptr if an EventFlag word was
* not requested when the FMQ was created. This method does not transfer
* ownership; the EventFlag word remains owned by the FMQ and will be freed
* when the FMQ is destroyed.
*/
uint32_t* getEventFlagWord() const;
/**
* Create a copy of the MQDescriptor for this object. This descriptor can be
* sent over IPC to allow constructing a remote object that will access the
* same queue over shared memory.
*
* @return ErasedMessageQueueDesc The copied descriptor, which must be freed
* by passing it to freeDesc.
*/
ErasedMessageQueueDesc* dupeDesc() const;
};