Devin Moore | 133cb5e | 2020-07-07 16:31:22 -0700 | [diff] [blame] | 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 | |
Devin Moore | ec271a7 | 2020-10-09 10:42:57 -0700 | [diff] [blame] | 17 | #include <aidl/android/hardware/common/fmq/MQDescriptor.h> |
Devin Moore | 133cb5e | 2020-07-07 16:31:22 -0700 | [diff] [blame] | 18 | #include <cutils/native_handle.h> |
| 19 | #include <fmq/MQDescriptorBase.h> |
Devin Moore | 7c04cfe | 2020-08-17 14:37:13 -0700 | [diff] [blame] | 20 | #include <limits> |
Devin Moore | 1b2d0a6 | 2020-09-22 17:20:54 +0000 | [diff] [blame] | 21 | #include <type_traits> |
Devin Moore | 7c04cfe | 2020-08-17 14:37:13 -0700 | [diff] [blame] | 22 | |
| 23 | namespace android { |
Devin Moore | 7c04cfe | 2020-08-17 14:37:13 -0700 | [diff] [blame] | 24 | namespace details { |
Devin Moore | 133cb5e | 2020-07-07 16:31:22 -0700 | [diff] [blame] | 25 | |
Devin Moore | ec271a7 | 2020-10-09 10:42:57 -0700 | [diff] [blame] | 26 | using aidl::android::hardware::common::fmq::GrantorDescriptor; |
| 27 | using aidl::android::hardware::common::fmq::MQDescriptor; |
| 28 | using aidl::android::hardware::common::fmq::SynchronizedReadWrite; |
| 29 | using aidl::android::hardware::common::fmq::UnsynchronizedWrite; |
Devin Moore | 133cb5e | 2020-07-07 16:31:22 -0700 | [diff] [blame] | 30 | using android::hardware::MQFlavor; |
| 31 | |
Devin Moore | 133cb5e | 2020-07-07 16:31:22 -0700 | [diff] [blame] | 32 | template <typename T, MQFlavor flavor> |
| 33 | struct AidlMQDescriptorShim { |
| 34 | // Takes ownership of handle |
Gareth Fenn | 1af2546 | 2020-11-11 20:46:32 +0000 | [diff] [blame] | 35 | AidlMQDescriptorShim(const std::vector<android::hardware::GrantorDescriptor>& grantors, |
| 36 | native_handle_t* nHandle, size_t size); |
| 37 | |
| 38 | // Takes ownership of handle |
Devin Moore | 1b2d0a6 | 2020-09-22 17:20:54 +0000 | [diff] [blame] | 39 | AidlMQDescriptorShim( |
| 40 | const MQDescriptor< |
| 41 | T, typename std::conditional<flavor == hardware::kSynchronizedReadWrite, |
| 42 | SynchronizedReadWrite, UnsynchronizedWrite>::type>& |
| 43 | desc); |
Devin Moore | 133cb5e | 2020-07-07 16:31:22 -0700 | [diff] [blame] | 44 | |
| 45 | // Takes ownership of handle |
| 46 | AidlMQDescriptorShim(size_t bufferSize, native_handle_t* nHandle, size_t messageSize, |
| 47 | bool configureEventFlag = false); |
| 48 | |
| 49 | explicit AidlMQDescriptorShim(const AidlMQDescriptorShim& other) |
| 50 | : AidlMQDescriptorShim(0, nullptr, 0) { |
| 51 | *this = other; |
| 52 | } |
| 53 | AidlMQDescriptorShim& operator=(const AidlMQDescriptorShim& other); |
| 54 | |
| 55 | ~AidlMQDescriptorShim(); |
| 56 | |
| 57 | size_t getSize() const; |
| 58 | |
| 59 | size_t getQuantum() const; |
| 60 | |
Devin Moore | 7c04cfe | 2020-08-17 14:37:13 -0700 | [diff] [blame] | 61 | uint32_t getFlags() const; |
Devin Moore | 133cb5e | 2020-07-07 16:31:22 -0700 | [diff] [blame] | 62 | |
| 63 | bool isHandleValid() const { return mHandle != nullptr; } |
| 64 | size_t countGrantors() const { return mGrantors.size(); } |
| 65 | |
Devin Moore | 7c04cfe | 2020-08-17 14:37:13 -0700 | [diff] [blame] | 66 | inline const std::vector<android::hardware::GrantorDescriptor>& grantors() const { |
| 67 | return mGrantors; |
| 68 | } |
Devin Moore | 133cb5e | 2020-07-07 16:31:22 -0700 | [diff] [blame] | 69 | |
| 70 | inline const ::native_handle_t* handle() const { return mHandle; } |
| 71 | |
| 72 | inline ::native_handle_t* handle() { return mHandle; } |
| 73 | |
| 74 | static const size_t kOffsetOfGrantors; |
| 75 | static const size_t kOffsetOfHandle; |
| 76 | |
| 77 | private: |
Devin Moore | 7c04cfe | 2020-08-17 14:37:13 -0700 | [diff] [blame] | 78 | std::vector<android::hardware::GrantorDescriptor> mGrantors; |
Devin Moore | 133cb5e | 2020-07-07 16:31:22 -0700 | [diff] [blame] | 79 | native_handle_t* mHandle = nullptr; |
Devin Moore | 7c04cfe | 2020-08-17 14:37:13 -0700 | [diff] [blame] | 80 | uint32_t mQuantum = 0; |
| 81 | uint32_t mFlags = 0; |
Devin Moore | 133cb5e | 2020-07-07 16:31:22 -0700 | [diff] [blame] | 82 | }; |
| 83 | |
| 84 | template <typename T, MQFlavor flavor> |
Devin Moore | 1b2d0a6 | 2020-09-22 17:20:54 +0000 | [diff] [blame] | 85 | AidlMQDescriptorShim<T, flavor>::AidlMQDescriptorShim( |
| 86 | const MQDescriptor<T, typename std::conditional<flavor == hardware::kSynchronizedReadWrite, |
| 87 | SynchronizedReadWrite, |
| 88 | UnsynchronizedWrite>::type>& desc) |
Devin Moore | 133cb5e | 2020-07-07 16:31:22 -0700 | [diff] [blame] | 89 | : mQuantum(desc.quantum), mFlags(desc.flags) { |
Devin Moore | 7c04cfe | 2020-08-17 14:37:13 -0700 | [diff] [blame] | 90 | if (desc.quantum < 0 || desc.flags < 0) { |
| 91 | // MQDescriptor uses signed integers, but the values must be positive. |
| 92 | hardware::details::logError("Invalid MQDescriptor. Values must be positive. quantum: " + |
| 93 | std::to_string(desc.quantum) + |
| 94 | ". flags: " + std::to_string(desc.flags)); |
| 95 | return; |
| 96 | } |
Devin Moore | 133cb5e | 2020-07-07 16:31:22 -0700 | [diff] [blame] | 97 | |
| 98 | mGrantors.resize(desc.grantors.size()); |
| 99 | for (size_t i = 0; i < desc.grantors.size(); ++i) { |
Devin Moore | d7e702b | 2021-01-18 16:10:37 -0800 | [diff] [blame] | 100 | if (desc.grantors[i].offset < 0 || desc.grantors[i].extent < 0 || |
| 101 | desc.grantors[i].fdIndex < 0) { |
Devin Moore | 7c04cfe | 2020-08-17 14:37:13 -0700 | [diff] [blame] | 102 | // GrantorDescriptor uses signed integers, but the values must be positive. |
| 103 | // Return before setting up the native_handle to make this invalid. |
| 104 | hardware::details::logError( |
| 105 | "Invalid MQDescriptor grantors. Values must be positive. Grantor index: " + |
| 106 | std::to_string(i) + ". offset: " + std::to_string(desc.grantors[i].offset) + |
| 107 | ". extent: " + std::to_string(desc.grantors[i].extent)); |
| 108 | return; |
| 109 | } |
| 110 | mGrantors[i].flags = 0; |
Devin Moore | d7e702b | 2021-01-18 16:10:37 -0800 | [diff] [blame] | 111 | mGrantors[i].fdIndex = desc.grantors[i].fdIndex; |
Devin Moore | 7c04cfe | 2020-08-17 14:37:13 -0700 | [diff] [blame] | 112 | mGrantors[i].offset = desc.grantors[i].offset; |
| 113 | mGrantors[i].extent = desc.grantors[i].extent; |
Devin Moore | 133cb5e | 2020-07-07 16:31:22 -0700 | [diff] [blame] | 114 | } |
Devin Moore | 7c04cfe | 2020-08-17 14:37:13 -0700 | [diff] [blame] | 115 | |
Devin Moore | d7e702b | 2021-01-18 16:10:37 -0800 | [diff] [blame] | 116 | mHandle = native_handle_create(desc.handle.fds.size() /* num fds */, |
| 117 | desc.handle.ints.size() /* num ints */); |
Devin Moore | 7c04cfe | 2020-08-17 14:37:13 -0700 | [diff] [blame] | 118 | if (mHandle == nullptr) { |
| 119 | hardware::details::logError("Null native_handle_t"); |
| 120 | return; |
| 121 | } |
Devin Moore | d7e702b | 2021-01-18 16:10:37 -0800 | [diff] [blame] | 122 | int data_index = 0; |
| 123 | for (const auto& fd : desc.handle.fds) { |
| 124 | mHandle->data[data_index] = dup(fd.get()); |
| 125 | data_index++; |
| 126 | } |
| 127 | for (const auto& data_int : desc.handle.ints) { |
| 128 | mHandle->data[data_index] = data_int; |
| 129 | data_index++; |
| 130 | } |
Devin Moore | 133cb5e | 2020-07-07 16:31:22 -0700 | [diff] [blame] | 131 | } |
| 132 | |
| 133 | template <typename T, MQFlavor flavor> |
Gareth Fenn | 1af2546 | 2020-11-11 20:46:32 +0000 | [diff] [blame] | 134 | AidlMQDescriptorShim<T, flavor>::AidlMQDescriptorShim( |
| 135 | const std::vector<android::hardware::GrantorDescriptor>& grantors, native_handle_t* nhandle, |
| 136 | size_t size) |
| 137 | : mGrantors(grantors), |
| 138 | mHandle(nhandle), |
| 139 | mQuantum(static_cast<uint32_t>(size)), |
| 140 | mFlags(flavor) {} |
| 141 | |
| 142 | template <typename T, MQFlavor flavor> |
Devin Moore | 133cb5e | 2020-07-07 16:31:22 -0700 | [diff] [blame] | 143 | AidlMQDescriptorShim<T, flavor>& AidlMQDescriptorShim<T, flavor>::operator=( |
| 144 | const AidlMQDescriptorShim& other) { |
| 145 | mGrantors = other.mGrantors; |
| 146 | if (mHandle != nullptr) { |
| 147 | native_handle_close(mHandle); |
| 148 | native_handle_delete(mHandle); |
| 149 | mHandle = nullptr; |
| 150 | } |
| 151 | mQuantum = other.mQuantum; |
| 152 | mFlags = other.mFlags; |
| 153 | |
| 154 | if (other.mHandle != nullptr) { |
| 155 | mHandle = native_handle_create(other.mHandle->numFds, other.mHandle->numInts); |
| 156 | |
| 157 | for (int i = 0; i < other.mHandle->numFds; ++i) { |
| 158 | mHandle->data[i] = dup(other.mHandle->data[i]); |
| 159 | } |
| 160 | |
| 161 | memcpy(&mHandle->data[other.mHandle->numFds], &other.mHandle->data[other.mHandle->numFds], |
| 162 | static_cast<size_t>(other.mHandle->numInts) * sizeof(int)); |
| 163 | } |
| 164 | |
| 165 | return *this; |
| 166 | } |
| 167 | |
| 168 | template <typename T, MQFlavor flavor> |
| 169 | AidlMQDescriptorShim<T, flavor>::AidlMQDescriptorShim(size_t bufferSize, native_handle_t* nHandle, |
Devin Moore | 3c10357 | 2021-04-01 08:58:13 -0700 | [diff] [blame] | 170 | size_t messageSize, bool configureEventFlag) |
| 171 | : mHandle(nHandle), mQuantum(messageSize), mFlags(flavor) { |
Devin Moore | 7c04cfe | 2020-08-17 14:37:13 -0700 | [diff] [blame] | 172 | /* |
| 173 | * TODO(b/165674950) Since AIDL does not support unsigned integers, it can only support |
| 174 | * The offset of EventFlag word needs to fit into an int32_t in MQDescriptor. This word comes |
| 175 | * after the readPtr, writePtr, and dataBuffer. |
| 176 | */ |
| 177 | bool overflow = bufferSize > std::numeric_limits<uint64_t>::max() - |
| 178 | (sizeof(hardware::details::RingBufferPosition) + |
| 179 | sizeof(hardware::details::RingBufferPosition)); |
| 180 | uint64_t largestOffset = hardware::details::alignToWordBoundary( |
| 181 | sizeof(hardware::details::RingBufferPosition) + |
| 182 | sizeof(hardware::details::RingBufferPosition) + bufferSize); |
| 183 | if (overflow || largestOffset > std::numeric_limits<int32_t>::max() || |
| 184 | messageSize > std::numeric_limits<int32_t>::max()) { |
| 185 | hardware::details::logError( |
| 186 | "Queue size is too large. Message size: " + std::to_string(messageSize) + |
| 187 | " bytes. Data buffer size: " + std::to_string(bufferSize) + " bytes. Max size: " + |
| 188 | std::to_string(std::numeric_limits<int32_t>::max()) + " bytes."); |
| 189 | return; |
| 190 | } |
| 191 | |
Devin Moore | 133cb5e | 2020-07-07 16:31:22 -0700 | [diff] [blame] | 192 | /* |
| 193 | * If configureEventFlag is true, allocate an additional spot in mGrantor |
| 194 | * for containing the fd and offset for mmapping the EventFlag word. |
| 195 | */ |
| 196 | mGrantors.resize(configureEventFlag ? hardware::details::kMinGrantorCountForEvFlagSupport |
| 197 | : hardware::details::kMinGrantorCount); |
| 198 | |
| 199 | size_t memSize[] = { |
| 200 | sizeof(hardware::details::RingBufferPosition), /* memory to be allocated for read |
| 201 | * pointer counter |
| 202 | */ |
| 203 | sizeof(hardware::details::RingBufferPosition), /* memory to be allocated for write |
| 204 | pointer counter */ |
| 205 | bufferSize, /* memory to be allocated for data buffer */ |
| 206 | sizeof(std::atomic<uint32_t>) /* memory to be allocated for EventFlag word */ |
| 207 | }; |
| 208 | |
| 209 | /* |
| 210 | * Create a default grantor descriptor for read, write pointers and |
| 211 | * the data buffer. fdIndex parameter is set to 0 by default and |
| 212 | * the offset for each grantor is contiguous. |
| 213 | */ |
| 214 | for (size_t grantorPos = 0, offset = 0; grantorPos < mGrantors.size(); |
| 215 | offset += memSize[grantorPos++]) { |
| 216 | mGrantors[grantorPos] = { |
| 217 | 0 /* grantor flags */, 0 /* fdIndex */, |
Devin Moore | 7c04cfe | 2020-08-17 14:37:13 -0700 | [diff] [blame] | 218 | static_cast<uint32_t>(hardware::details::alignToWordBoundary(offset)), |
| 219 | memSize[grantorPos]}; |
Devin Moore | 133cb5e | 2020-07-07 16:31:22 -0700 | [diff] [blame] | 220 | } |
| 221 | } |
| 222 | |
| 223 | template <typename T, MQFlavor flavor> |
| 224 | AidlMQDescriptorShim<T, flavor>::~AidlMQDescriptorShim() { |
| 225 | if (mHandle != nullptr) { |
| 226 | native_handle_close(mHandle); |
| 227 | native_handle_delete(mHandle); |
| 228 | } |
| 229 | } |
| 230 | |
| 231 | template <typename T, MQFlavor flavor> |
| 232 | size_t AidlMQDescriptorShim<T, flavor>::getSize() const { |
| 233 | return mGrantors[hardware::details::DATAPTRPOS].extent; |
| 234 | } |
| 235 | |
| 236 | template <typename T, MQFlavor flavor> |
| 237 | size_t AidlMQDescriptorShim<T, flavor>::getQuantum() const { |
| 238 | return mQuantum; |
| 239 | } |
| 240 | |
| 241 | template <typename T, MQFlavor flavor> |
Devin Moore | 7c04cfe | 2020-08-17 14:37:13 -0700 | [diff] [blame] | 242 | uint32_t AidlMQDescriptorShim<T, flavor>::getFlags() const { |
Devin Moore | 133cb5e | 2020-07-07 16:31:22 -0700 | [diff] [blame] | 243 | return mFlags; |
| 244 | } |
| 245 | |
| 246 | template <typename T, MQFlavor flavor> |
| 247 | std::string toString(const AidlMQDescriptorShim<T, flavor>& q) { |
| 248 | std::string os; |
| 249 | if (flavor & hardware::kSynchronizedReadWrite) { |
| 250 | os += "fmq_sync"; |
| 251 | } |
| 252 | if (flavor & hardware::kUnsynchronizedWrite) { |
| 253 | os += "fmq_unsync"; |
| 254 | } |
| 255 | os += " {" + toString(q.grantors().size()) + " grantor(s), " + |
| 256 | "size = " + toString(q.getSize()) + ", .handle = " + toString(q.handle()) + |
| 257 | ", .quantum = " + toString(q.getQuantum()) + "}"; |
| 258 | return os; |
| 259 | } |
| 260 | |
| 261 | } // namespace details |
| 262 | } // namespace android |