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