summaryrefslogtreecommitdiff
path: root/include/fmq/AidlMessageQueue.h
blob: 0536d6abe684ef048c46e9f73fe77507793d01ab (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/*
 * Copyright (C) 2020 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.
 */

#pragma once

#include <aidl/android/hardware/common/fmq/MQDescriptor.h>
#include <aidl/android/hardware/common/fmq/SynchronizedReadWrite.h>
#include <aidl/android/hardware/common/fmq/UnsynchronizedWrite.h>
#include <cutils/native_handle.h>
#include <fmq/AidlMQDescriptorShim.h>
#include <fmq/MessageQueueBase.h>
#include <utils/Log.h>
#include <type_traits>

namespace android {

using aidl::android::hardware::common::fmq::MQDescriptor;
using aidl::android::hardware::common::fmq::SynchronizedReadWrite;
using aidl::android::hardware::common::fmq::UnsynchronizedWrite;
using android::details::AidlMQDescriptorShim;
using android::hardware::MQFlavor;

template <typename T>
struct FlavorTypeToValue;

template <>
struct FlavorTypeToValue<SynchronizedReadWrite> {
    static constexpr MQFlavor value = hardware::kSynchronizedReadWrite;
};

template <>
struct FlavorTypeToValue<UnsynchronizedWrite> {
    static constexpr MQFlavor value = hardware::kUnsynchronizedWrite;
};

typedef uint64_t RingBufferPosition;

/*
 * AIDL parcelables will have the typedef fixed_size. It is std::true_type when the
 * parcelable is annotated with @FixedSize, and std::false_type when not. Other types
 * should not have the fixed_size typedef, so they will always resolve to std::false_type.
 */
template <typename T, typename = void>
struct has_typedef_fixed_size : std::false_type {};

template <typename T>
struct has_typedef_fixed_size<T, std::void_t<typename T::fixed_size>> : T::fixed_size {};

#define STATIC_AIDL_TYPE_CHECK(T)                                                                  \
    static_assert(has_typedef_fixed_size<T>::value == true || std::is_fundamental<T>::value ||     \
                          std::is_enum<T>::value,                                                  \
                  "Only fundamental types, enums, and AIDL parcelables annotated with @FixedSize " \
                  "and built for the NDK backend are supported as payload types(T).");

template <typename T, typename U>
struct AidlMessageQueue final
    : public MessageQueueBase<AidlMQDescriptorShim, T, FlavorTypeToValue<U>::value> {
    STATIC_AIDL_TYPE_CHECK(T);
    typedef AidlMQDescriptorShim<T, FlavorTypeToValue<U>::value> Descriptor;
    /**
     * This constructor uses the external descriptor used with AIDL interfaces.
     * It will create an FMQ based on the descriptor that was obtained from
     * another FMQ instance for communication.
     *
     * @param desc Descriptor from another FMQ that contains all of the
     * information required to create a new instance of that queue.
     * @param resetPointers Boolean indicating whether the read/write pointers
     * should be reset or not.
     */
    AidlMessageQueue(const MQDescriptor<T, U>& desc, bool resetPointers = true);
    ~AidlMessageQueue() = default;

    /**
     * This constructor uses Ashmem shared memory to create an FMQ
     * that can contain a maximum of 'numElementsInQueue' elements of type T.
     *
     * @param numElementsInQueue Capacity of the AidlMessageQueue in terms of T.
     * @param configureEventFlagWord Boolean that specifies if memory should
     * also be allocated and mapped for an EventFlag word.
     * @param bufferFd User-supplied file descriptor to map the memory for the ringbuffer
     * By default, bufferFd=-1 means library will allocate ashmem region for ringbuffer.
     * MessageQueue takes ownership of the file descriptor.
     * @param bufferSize size of buffer in bytes that bufferFd represents. This
     * size must be larger than or equal to (numElementsInQueue * sizeof(T)).
     * Otherwise, operations will cause out-of-bounds memory access.
     */
    AidlMessageQueue(size_t numElementsInQueue, bool configureEventFlagWord,
                     android::base::unique_fd bufferFd, size_t bufferSize);

    AidlMessageQueue(size_t numElementsInQueue, bool configureEventFlagWord = false)
        : AidlMessageQueue(numElementsInQueue, configureEventFlagWord, android::base::unique_fd(),
                           0) {}

    MQDescriptor<T, U> dupeDesc();

  private:
    AidlMessageQueue(const AidlMessageQueue& other) = delete;
    AidlMessageQueue& operator=(const AidlMessageQueue& other) = delete;
    AidlMessageQueue() = delete;
};

template <typename T, typename U>
AidlMessageQueue<T, U>::AidlMessageQueue(const MQDescriptor<T, U>& desc, bool resetPointers)
    : MessageQueueBase<AidlMQDescriptorShim, T, FlavorTypeToValue<U>::value>(Descriptor(desc),
                                                                             resetPointers) {}

template <typename T, typename U>
AidlMessageQueue<T, U>::AidlMessageQueue(size_t numElementsInQueue, bool configureEventFlagWord,
                                         android::base::unique_fd bufferFd, size_t bufferSize)
    : MessageQueueBase<AidlMQDescriptorShim, T, FlavorTypeToValue<U>::value>(
              numElementsInQueue, configureEventFlagWord, std::move(bufferFd), bufferSize) {}

template <typename T, typename U>
MQDescriptor<T, U> AidlMessageQueue<T, U>::dupeDesc() {
    auto* shim = MessageQueueBase<AidlMQDescriptorShim, T, FlavorTypeToValue<U>::value>::getDesc();
    if (shim) {
        std::vector<aidl::android::hardware::common::fmq::GrantorDescriptor> grantors;
        for (const auto& grantor : shim->grantors()) {
            grantors.push_back(aidl::android::hardware::common::fmq::GrantorDescriptor{
                    .fdIndex = static_cast<int32_t>(grantor.fdIndex),
                    .offset = static_cast<int32_t>(grantor.offset),
                    .extent = static_cast<int64_t>(grantor.extent)});
        }
        std::vector<ndk::ScopedFileDescriptor> fds;
        std::vector<int> ints;
        int data_index = 0;
        for (; data_index < shim->handle()->numFds; data_index++) {
            fds.push_back(ndk::ScopedFileDescriptor(dup(shim->handle()->data[data_index])));
        }
        for (; data_index < shim->handle()->numFds + shim->handle()->numInts; data_index++) {
            ints.push_back(shim->handle()->data[data_index]);
        }
        return MQDescriptor<T, U>{
                .quantum = static_cast<int32_t>(shim->getQuantum()),
                .grantors = grantors,
                .flags = static_cast<int32_t>(shim->getFlags()),
                .handle = {std::move(fds), std::move(ints)},
        };
    } else {
        return MQDescriptor<T, U>();
    }
}

}  // namespace android