1 /* 2 * Copyright (C) 2020 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 17 #pragma once 18 19 #include <aidl/android/hardware/common/fmq/MQDescriptor.h> 20 #include <aidl/android/hardware/common/fmq/SynchronizedReadWrite.h> 21 #include <aidl/android/hardware/common/fmq/UnsynchronizedWrite.h> 22 #include <cutils/native_handle.h> 23 #include <fmq/AidlMQDescriptorShim.h> 24 #include <fmq/MessageQueueBase.h> 25 #include <utils/Log.h> 26 #include <type_traits> 27 28 namespace android { 29 30 using aidl::android::hardware::common::fmq::MQDescriptor; 31 using aidl::android::hardware::common::fmq::SynchronizedReadWrite; 32 using aidl::android::hardware::common::fmq::UnsynchronizedWrite; 33 using android::details::AidlMQDescriptorShim; 34 using android::hardware::MQFlavor; 35 36 template <typename T> 37 struct FlavorTypeToValue; 38 39 template <> 40 struct FlavorTypeToValue<SynchronizedReadWrite> { 41 static constexpr MQFlavor value = hardware::kSynchronizedReadWrite; 42 }; 43 44 template <> 45 struct FlavorTypeToValue<UnsynchronizedWrite> { 46 static constexpr MQFlavor value = hardware::kUnsynchronizedWrite; 47 }; 48 49 typedef uint64_t RingBufferPosition; 50 51 /* 52 * AIDL parcelables will have the typedef fixed_size. It is std::true_type when the 53 * parcelable is annotated with @FixedSize, and std::false_type when not. Other types 54 * should not have the fixed_size typedef, so they will always resolve to std::false_type. 55 */ 56 template <typename T, typename = void> 57 struct has_typedef_fixed_size : std::false_type {}; 58 59 template <typename T> 60 struct has_typedef_fixed_size<T, std::void_t<typename T::fixed_size>> : T::fixed_size {}; 61 62 #define STATIC_AIDL_TYPE_CHECK(T) \ 63 static_assert(has_typedef_fixed_size<T>::value == true || std::is_fundamental<T>::value || \ 64 std::is_enum<T>::value, \ 65 "Only fundamental types, enums, and AIDL parcelables annotated with @FixedSize " \ 66 "and built for the NDK backend are supported as payload types(T)."); 67 68 template <typename T, typename U> 69 struct AidlMessageQueue final 70 : public MessageQueueBase<AidlMQDescriptorShim, T, FlavorTypeToValue<U>::value> { 71 STATIC_AIDL_TYPE_CHECK(T); 72 typedef AidlMQDescriptorShim<T, FlavorTypeToValue<U>::value> Descriptor; 73 /** 74 * This constructor uses the external descriptor used with AIDL interfaces. 75 * It will create an FMQ based on the descriptor that was obtained from 76 * another FMQ instance for communication. 77 * 78 * @param desc Descriptor from another FMQ that contains all of the 79 * information required to create a new instance of that queue. 80 * @param resetPointers Boolean indicating whether the read/write pointers 81 * should be reset or not. 82 */ 83 AidlMessageQueue(const MQDescriptor<T, U>& desc, bool resetPointers = true); 84 ~AidlMessageQueue() = default; 85 86 /** 87 * This constructor uses Ashmem shared memory to create an FMQ 88 * that can contain a maximum of 'numElementsInQueue' elements of type T. 89 * 90 * @param numElementsInQueue Capacity of the AidlMessageQueue in terms of T. 91 * @param configureEventFlagWord Boolean that specifies if memory should 92 * also be allocated and mapped for an EventFlag word. 93 * @param bufferFd User-supplied file descriptor to map the memory for the ringbuffer 94 * By default, bufferFd=-1 means library will allocate ashmem region for ringbuffer. 95 * MessageQueue takes ownership of the file descriptor. 96 * @param bufferSize size of buffer in bytes that bufferFd represents. This 97 * size must be larger than or equal to (numElementsInQueue * sizeof(T)). 98 * Otherwise, operations will cause out-of-bounds memory access. 99 */ 100 AidlMessageQueue(size_t numElementsInQueue, bool configureEventFlagWord, 101 android::base::unique_fd bufferFd, size_t bufferSize); 102 103 AidlMessageQueue(size_t numElementsInQueue, bool configureEventFlagWord = false) 104 : AidlMessageQueue(numElementsInQueue, configureEventFlagWord, android::base::unique_fd(), 105 0) {} 106 107 MQDescriptor<T, U> dupeDesc(); 108 109 private: 110 AidlMessageQueue(const AidlMessageQueue& other) = delete; 111 AidlMessageQueue& operator=(const AidlMessageQueue& other) = delete; 112 AidlMessageQueue() = delete; 113 }; 114 115 template <typename T, typename U> 116 AidlMessageQueue<T, U>::AidlMessageQueue(const MQDescriptor<T, U>& desc, bool resetPointers) 117 : MessageQueueBase<AidlMQDescriptorShim, T, FlavorTypeToValue<U>::value>(Descriptor(desc), 118 resetPointers) {} 119 120 template <typename T, typename U> 121 AidlMessageQueue<T, U>::AidlMessageQueue(size_t numElementsInQueue, bool configureEventFlagWord, 122 android::base::unique_fd bufferFd, size_t bufferSize) 123 : MessageQueueBase<AidlMQDescriptorShim, T, FlavorTypeToValue<U>::value>( 124 numElementsInQueue, configureEventFlagWord, std::move(bufferFd), bufferSize) {} 125 126 template <typename T, typename U> 127 MQDescriptor<T, U> AidlMessageQueue<T, U>::dupeDesc() { 128 auto* shim = MessageQueueBase<AidlMQDescriptorShim, T, FlavorTypeToValue<U>::value>::getDesc(); 129 if (shim) { 130 std::vector<aidl::android::hardware::common::fmq::GrantorDescriptor> grantors; 131 for (const auto& grantor : shim->grantors()) { 132 grantors.push_back(aidl::android::hardware::common::fmq::GrantorDescriptor{ 133 .fdIndex = static_cast<int32_t>(grantor.fdIndex), 134 .offset = static_cast<int32_t>(grantor.offset), 135 .extent = static_cast<int64_t>(grantor.extent)}); 136 } 137 std::vector<ndk::ScopedFileDescriptor> fds; 138 std::vector<int> ints; 139 int data_index = 0; 140 for (; data_index < shim->handle()->numFds; data_index++) { 141 fds.push_back(ndk::ScopedFileDescriptor(dup(shim->handle()->data[data_index]))); 142 } 143 for (; data_index < shim->handle()->numFds + shim->handle()->numInts; data_index++) { 144 ints.push_back(shim->handle()->data[data_index]); 145 } 146 return MQDescriptor<T, U>{ 147 .quantum = static_cast<int32_t>(shim->getQuantum()), 148 .grantors = grantors, 149 .flags = static_cast<int32_t>(shim->getFlags()), 150 .handle = {std::move(fds), std::move(ints)}, 151 }; 152 } else { 153 return MQDescriptor<T, U>(); 154 } 155 } 156 157 } // namespace android 158