xref: /aosp_15_r20/system/libfmq/include/fmq/AidlMessageQueueBase.h (revision be431cd81a9a2349eaea34eb56fcf6d1608da596)
1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #pragma once
17 #include <cutils/native_handle.h>
18 #include <fmq/MessageQueueBase.h>
19 #include <utils/Log.h>
20 #include <type_traits>
21 
22 using android::hardware::MQFlavor;
23 
24 typedef uint64_t RingBufferPosition;
25 
26 namespace android {
27 
28 template <typename T>
29 struct FlavorTypeToValue;
30 
31 /*
32  * AIDL parcelables will have the typedef fixed_size. It is std::true_type when the
33  * parcelable is annotated with @FixedSize, and std::false_type when not. Other types
34  * should not have the fixed_size typedef, so they will always resolve to std::false_type.
35  */
36 template <typename T, typename = void>
37 struct has_typedef_fixed_size : std::false_type {};
38 
39 template <typename T>
40 struct has_typedef_fixed_size<T, std::void_t<typename T::fixed_size>> : T::fixed_size {};
41 
42 #define STATIC_AIDL_TYPE_CHECK(T)                                                                  \
43     static_assert(has_typedef_fixed_size<T>::value == true || std::is_fundamental<T>::value ||     \
44                           std::is_enum<T>::value,                                                  \
45                   "Only fundamental types, enums, and AIDL parcelables annotated with @FixedSize " \
46                   "and built for the NDK backend are supported as payload types(T).");
47 
48 template <template <typename> class C1>
49 struct Base {};
50 
51 template <typename T, typename BaseTypes, typename U>
52 struct Queue : Base<BaseTypes::template B> {};
53 
54 template <typename T, typename U, typename BackendTypes>
55 struct AidlMessageQueueBase
56     : public MessageQueueBase<BackendTypes::template AidlMQDescriptorShimType, T,
57                               FlavorTypeToValue<U>::value> {
58     STATIC_AIDL_TYPE_CHECK(T);
59     typedef typename BackendTypes::FileDescriptorType FileDescriptorType;
60     typedef typename BackendTypes::GrantorDescriptorType GrantorDescriptorType;
61     typedef typename BackendTypes::template AidlMQDescriptorShimType<T, FlavorTypeToValue<U>::value>
62             Descriptor;
63     /**
64      * This constructor uses the external descriptor used with AIDL interfaces.
65      * It will create an FMQ based on the descriptor that was obtained from
66      * another FMQ instance for communication.
67      *
68      * @param desc Descriptor from another FMQ that contains all of the
69      * information required to create a new instance of that queue.
70      * @param resetPointers Boolean indicating whether the read/write pointers
71      * should be reset or not.
72      */
73     AidlMessageQueueBase(const typename BackendTypes::template MQDescriptorType<T, U>& desc,
74                          bool resetPointers = true);
75     ~AidlMessageQueueBase() = default;
76 
77     /**
78      * This constructor uses Ashmem shared memory to create an FMQ
79      * that can contain a maximum of 'numElementsInQueue' elements of type T.
80      *
81      * @param numElementsInQueue Capacity of the AidlMessageQueueBase in terms of T.
82      * @param configureEventFlagWord Boolean that specifies if memory should
83      * also be allocated and mapped for an EventFlag word.
84      * @param bufferFd User-supplied file descriptor to map the memory for the ringbuffer
85      * By default, bufferFd=-1 means library will allocate ashmem region for ringbuffer.
86      * MessageQueue takes ownership of the file descriptor.
87      * @param bufferSize size of buffer in bytes that bufferFd represents. This
88      * size must be larger than or equal to (numElementsInQueue * sizeof(T)).
89      * Otherwise, operations will cause out-of-bounds memory access.
90      */
91     AidlMessageQueueBase(size_t numElementsInQueue, bool configureEventFlagWord,
92                          android::base::unique_fd bufferFd, size_t bufferSize);
93 
94     AidlMessageQueueBase(size_t numElementsInQueue, bool configureEventFlagWord = false)
95         : AidlMessageQueueBase(numElementsInQueue, configureEventFlagWord,
96                                android::base::unique_fd(), 0) {}
97 
98     template <typename V = T>
99     AidlMessageQueueBase(size_t numElementsInQueue, bool configureEventFlagWord = false,
100                          std::enable_if_t<std::is_same_v<V, MQErased>, size_t> quantum = sizeof(T))
101         : AidlMessageQueueBase(numElementsInQueue, configureEventFlagWord,
102                                android::base::unique_fd(), 0, quantum) {}
103 
104     template <typename V = T>
105     AidlMessageQueueBase(size_t numElementsInQueue, bool configureEventFlagWord,
106                          android::base::unique_fd bufferFd, size_t bufferSize,
107                          std::enable_if_t<std::is_same_v<V, MQErased>, size_t> quantum);
108     typename BackendTypes::template MQDescriptorType<T, U> dupeDesc() const;
109 
110   private:
111     AidlMessageQueueBase(const AidlMessageQueueBase& other) = delete;
112     AidlMessageQueueBase& operator=(const AidlMessageQueueBase& other) = delete;
113     AidlMessageQueueBase() = delete;
114 };
115 
116 template <typename T, typename U, typename BackendTypes>
117 AidlMessageQueueBase<T, U, BackendTypes>::AidlMessageQueueBase(
118         const typename BackendTypes::template MQDescriptorType<T, U>& desc, bool resetPointers)
119     : MessageQueueBase<BackendTypes::template AidlMQDescriptorShimType, T,
120                        FlavorTypeToValue<U>::value>(Descriptor(desc), resetPointers) {}
121 
122 template <typename T, typename U, typename BackendTypes>
123 AidlMessageQueueBase<T, U, BackendTypes>::AidlMessageQueueBase(size_t numElementsInQueue,
124                                                                bool configureEventFlagWord,
125                                                                android::base::unique_fd bufferFd,
126                                                                size_t bufferSize)
127     : MessageQueueBase<BackendTypes::template AidlMQDescriptorShimType, T,
128                        FlavorTypeToValue<U>::value>(numElementsInQueue, configureEventFlagWord,
129                                                     std::move(bufferFd), bufferSize) {}
130 
131 template <typename T, typename U, typename BackendTypes>
132 template <typename V>
133 AidlMessageQueueBase<T, U, BackendTypes>::AidlMessageQueueBase(
134         size_t numElementsInQueue, bool configureEventFlagWord, android::base::unique_fd bufferFd,
135         size_t bufferSize, std::enable_if_t<std::is_same_v<V, MQErased>, size_t> quantum)
136     : MessageQueueBase<BackendTypes::template AidlMQDescriptorShimType, T,
137                        FlavorTypeToValue<U>::value>(numElementsInQueue, configureEventFlagWord,
138                                                     std::move(bufferFd), bufferSize, quantum) {}
139 
140 template <typename T, typename U, typename BackendTypes>
141 typename BackendTypes::template MQDescriptorType<T, U>
142 AidlMessageQueueBase<T, U, BackendTypes>::dupeDesc() const {
143     auto* shim = MessageQueueBase<BackendTypes::template AidlMQDescriptorShimType, T,
144                                   FlavorTypeToValue<U>::value>::getDesc();
145     if (shim) {
146         std::vector<GrantorDescriptorType> grantors;
147         for (const auto& grantor : shim->grantors()) {
148             GrantorDescriptorType gd;
149             gd.fdIndex = static_cast<int32_t>(grantor.fdIndex);
150             gd.offset = static_cast<int32_t>(grantor.offset);
151             gd.extent = static_cast<int64_t>(grantor.extent);
152             grantors.push_back(gd);
153         }
154         std::vector<FileDescriptorType> fds;
155         std::vector<int> ints;
156         int data_index = 0;
157         for (; data_index < shim->handle()->numFds; data_index++) {
158             fds.push_back(BackendTypes::createFromInt(dup(shim->handle()->data[data_index])));
159         }
160         for (; data_index < shim->handle()->numFds + shim->handle()->numInts; data_index++) {
161             ints.push_back(shim->handle()->data[data_index]);
162         }
163         typename BackendTypes::template MQDescriptorType<T, U> desc;
164 
165         desc.grantors = grantors;
166         desc.handle.fds = std::move(fds);
167         desc.handle.ints = ints;
168         desc.quantum = static_cast<int32_t>(shim->getQuantum());
169         desc.flags = static_cast<int32_t>(shim->getFlags());
170         return desc;
171     } else {
172         return typename BackendTypes::template MQDescriptorType<T, U>();
173     }
174 }
175 
176 }  // namespace android
177