xref: /aosp_15_r20/system/libfmq/include/fmq/ConvertMQDescriptors.h (revision be431cd81a9a2349eaea34eb56fcf6d1608da596)
1*be431cd8SAndroid Build Coastguard Worker /*
2*be431cd8SAndroid Build Coastguard Worker  * Copyright (C) 2020 The Android Open Source Project
3*be431cd8SAndroid Build Coastguard Worker  *
4*be431cd8SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*be431cd8SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*be431cd8SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*be431cd8SAndroid Build Coastguard Worker  *
8*be431cd8SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*be431cd8SAndroid Build Coastguard Worker  *
10*be431cd8SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*be431cd8SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*be431cd8SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*be431cd8SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*be431cd8SAndroid Build Coastguard Worker  * limitations under the License.
15*be431cd8SAndroid Build Coastguard Worker  */
16*be431cd8SAndroid Build Coastguard Worker #pragma once
17*be431cd8SAndroid Build Coastguard Worker 
18*be431cd8SAndroid Build Coastguard Worker #include <aidl/android/hardware/common/fmq/MQDescriptor.h>
19*be431cd8SAndroid Build Coastguard Worker #include <aidl/android/hardware/common/fmq/SynchronizedReadWrite.h>
20*be431cd8SAndroid Build Coastguard Worker #include <aidl/android/hardware/common/fmq/UnsynchronizedWrite.h>
21*be431cd8SAndroid Build Coastguard Worker #include <cutils/native_handle.h>
22*be431cd8SAndroid Build Coastguard Worker #include <fmq/AidlMessageQueue.h>
23*be431cd8SAndroid Build Coastguard Worker #include <hidl/MQDescriptor.h>
24*be431cd8SAndroid Build Coastguard Worker 
25*be431cd8SAndroid Build Coastguard Worker namespace android {
26*be431cd8SAndroid Build Coastguard Worker using aidl::android::hardware::common::fmq::GrantorDescriptor;
27*be431cd8SAndroid Build Coastguard Worker using aidl::android::hardware::common::fmq::MQDescriptor;
28*be431cd8SAndroid Build Coastguard Worker using hardware::details::logError;
29*be431cd8SAndroid Build Coastguard Worker 
30*be431cd8SAndroid Build Coastguard Worker /**
31*be431cd8SAndroid Build Coastguard Worker  * This function converts a HIDL hardware::MQDescriptor to an AIDL
32*be431cd8SAndroid Build Coastguard Worker  * aidl::android::hardware::common::fmq::MQDescriptor for Fast
33*be431cd8SAndroid Build Coastguard Worker  * Message Queue.
34*be431cd8SAndroid Build Coastguard Worker  *
35*be431cd8SAndroid Build Coastguard Worker  * This is considered UNSAFE because it is not checking the offsets of each of the
36*be431cd8SAndroid Build Coastguard Worker  * paylod types' fields. In order for these objects to be passed through shared memory safely,
37*be431cd8SAndroid Build Coastguard Worker  * they must have the exact same memory layout. Same size, same alignment, and same
38*be431cd8SAndroid Build Coastguard Worker  * offsets for each field. Make sure this is the case before using this!
39*be431cd8SAndroid Build Coastguard Worker  * Same sized C++ fundamental types and enums with same sized backing types are OK.
40*be431cd8SAndroid Build Coastguard Worker  * Ex 1: uint64_t is compatible with int64_t
41*be431cd8SAndroid Build Coastguard Worker  * Ex 2:
42*be431cd8SAndroid Build Coastguard Worker  * @FixedSize parcelable Foo {
43*be431cd8SAndroid Build Coastguard Worker  *   int a;
44*be431cd8SAndroid Build Coastguard Worker  *   long b;
45*be431cd8SAndroid Build Coastguard Worker  *   MyEnum c; // backed by int32_t
46*be431cd8SAndroid Build Coastguard Worker  * }
47*be431cd8SAndroid Build Coastguard Worker  * struct Bar {
48*be431cd8SAndroid Build Coastguard Worker  *   int a;
49*be431cd8SAndroid Build Coastguard Worker  *   long b;
50*be431cd8SAndroid Build Coastguard Worker  *   YourEnum c; // backed by uint32_t
51*be431cd8SAndroid Build Coastguard Worker  * }
52*be431cd8SAndroid Build Coastguard Worker  * The two types above are compatible with each other as long as the fields have
53*be431cd8SAndroid Build Coastguard Worker  * the same offsets.
54*be431cd8SAndroid Build Coastguard Worker  *
55*be431cd8SAndroid Build Coastguard Worker  * Template params:
56*be431cd8SAndroid Build Coastguard Worker  *    HidlPayload - the type of the payload used for the HIDL MessageQueue
57*be431cd8SAndroid Build Coastguard Worker  *    AidlPayload - the type of the payload used for the AIDL AidlMessageQueue
58*be431cd8SAndroid Build Coastguard Worker  *    AidlFlavor - the flavor of the queues. Either SynchronizedReadWrite,
59*be431cd8SAndroid Build Coastguard Worker  *                 or UnsynchronizedWrite
60*be431cd8SAndroid Build Coastguard Worker  * Function params:
61*be431cd8SAndroid Build Coastguard Worker  *    hidlDesc - reference to the HIDL MQDescriptor to be copied from
62*be431cd8SAndroid Build Coastguard Worker  *    aidlDesc - pointer to the AIDL MQDescriptor to be copied to
63*be431cd8SAndroid Build Coastguard Worker  */
64*be431cd8SAndroid Build Coastguard Worker template <typename HidlPayload, typename AidlPayload, typename AidlFlavor>
unsafeHidlToAidlMQDescriptor(const hardware::MQDescriptor<HidlPayload,FlavorTypeToValue<AidlFlavor>::value> & hidlDesc,MQDescriptor<AidlPayload,AidlFlavor> * aidlDesc)65*be431cd8SAndroid Build Coastguard Worker bool unsafeHidlToAidlMQDescriptor(
66*be431cd8SAndroid Build Coastguard Worker         const hardware::MQDescriptor<HidlPayload, FlavorTypeToValue<AidlFlavor>::value>& hidlDesc,
67*be431cd8SAndroid Build Coastguard Worker         MQDescriptor<AidlPayload, AidlFlavor>* aidlDesc) {
68*be431cd8SAndroid Build Coastguard Worker     static_assert(sizeof(HidlPayload) == sizeof(AidlPayload),
69*be431cd8SAndroid Build Coastguard Worker                   "Payload types are definitely incompatible");
70*be431cd8SAndroid Build Coastguard Worker     static_assert(alignof(HidlPayload) == alignof(AidlPayload),
71*be431cd8SAndroid Build Coastguard Worker                   "Payload types are definitely incompatible");
72*be431cd8SAndroid Build Coastguard Worker     STATIC_AIDL_TYPE_CHECK(AidlPayload);
73*be431cd8SAndroid Build Coastguard Worker     if (!aidlDesc->grantors.empty()) {
74*be431cd8SAndroid Build Coastguard Worker         logError("Destination AIDL MQDescriptor should be empty, but already contains grantors.");
75*be431cd8SAndroid Build Coastguard Worker         return false;
76*be431cd8SAndroid Build Coastguard Worker     }
77*be431cd8SAndroid Build Coastguard Worker 
78*be431cd8SAndroid Build Coastguard Worker     for (const auto& grantor : hidlDesc.grantors()) {
79*be431cd8SAndroid Build Coastguard Worker         if (static_cast<int32_t>(grantor.offset) < 0 || static_cast<int64_t>(grantor.extent) < 0 ||
80*be431cd8SAndroid Build Coastguard Worker             static_cast<int64_t>(grantor.fdIndex) < 0) {
81*be431cd8SAndroid Build Coastguard Worker             logError(
82*be431cd8SAndroid Build Coastguard Worker                     "Unsafe static_cast of grantor fields. Either the hardware::MQDescriptor is "
83*be431cd8SAndroid Build Coastguard Worker                     "invalid, or the MessageQueue is too large to be described by AIDL.");
84*be431cd8SAndroid Build Coastguard Worker             return false;
85*be431cd8SAndroid Build Coastguard Worker         }
86*be431cd8SAndroid Build Coastguard Worker         aidlDesc->grantors.push_back(
87*be431cd8SAndroid Build Coastguard Worker                 GrantorDescriptor{.fdIndex = static_cast<int32_t>(grantor.fdIndex),
88*be431cd8SAndroid Build Coastguard Worker                                   .offset = static_cast<int32_t>(grantor.offset),
89*be431cd8SAndroid Build Coastguard Worker                                   .extent = static_cast<int64_t>(grantor.extent)});
90*be431cd8SAndroid Build Coastguard Worker     }
91*be431cd8SAndroid Build Coastguard Worker 
92*be431cd8SAndroid Build Coastguard Worker     std::vector<ndk::ScopedFileDescriptor> fds;
93*be431cd8SAndroid Build Coastguard Worker     std::vector<int> ints;
94*be431cd8SAndroid Build Coastguard Worker     int data_index = 0;
95*be431cd8SAndroid Build Coastguard Worker     for (; data_index < hidlDesc.handle()->numFds; data_index++) {
96*be431cd8SAndroid Build Coastguard Worker         fds.push_back(ndk::ScopedFileDescriptor(dup(hidlDesc.handle()->data[data_index])));
97*be431cd8SAndroid Build Coastguard Worker     }
98*be431cd8SAndroid Build Coastguard Worker     for (; data_index < hidlDesc.handle()->numFds + hidlDesc.handle()->numInts; data_index++) {
99*be431cd8SAndroid Build Coastguard Worker         ints.push_back(hidlDesc.handle()->data[data_index]);
100*be431cd8SAndroid Build Coastguard Worker     }
101*be431cd8SAndroid Build Coastguard Worker 
102*be431cd8SAndroid Build Coastguard Worker     aidlDesc->handle = {std::move(fds), std::move(ints)};
103*be431cd8SAndroid Build Coastguard Worker     if (static_cast<int32_t>(hidlDesc.getQuantum()) < 0 ||
104*be431cd8SAndroid Build Coastguard Worker         static_cast<int32_t>(hidlDesc.getFlags()) < 0) {
105*be431cd8SAndroid Build Coastguard Worker         logError(
106*be431cd8SAndroid Build Coastguard Worker                 "Unsafe static_cast of quantum or flags. Either the hardware::MQDescriptor is "
107*be431cd8SAndroid Build Coastguard Worker                 "invalid, or the MessageQueue is too large to be described by AIDL.");
108*be431cd8SAndroid Build Coastguard Worker         return false;
109*be431cd8SAndroid Build Coastguard Worker     }
110*be431cd8SAndroid Build Coastguard Worker     if (hidlDesc.getFlags() != FlavorTypeToValue<AidlFlavor>::value) {
111*be431cd8SAndroid Build Coastguard Worker         logError("hardware::MQDescriptor hidlDesc is invalid. Unexpected getFlags() value: " +
112*be431cd8SAndroid Build Coastguard Worker                  std::to_string(hidlDesc.getFlags()) +
113*be431cd8SAndroid Build Coastguard Worker                  ". Expected value: " + std::to_string(FlavorTypeToValue<AidlFlavor>::value));
114*be431cd8SAndroid Build Coastguard Worker         return false;
115*be431cd8SAndroid Build Coastguard Worker     }
116*be431cd8SAndroid Build Coastguard Worker     aidlDesc->quantum = static_cast<int32_t>(hidlDesc.getQuantum());
117*be431cd8SAndroid Build Coastguard Worker     aidlDesc->flags = static_cast<int32_t>(hidlDesc.getFlags());
118*be431cd8SAndroid Build Coastguard Worker     return true;
119*be431cd8SAndroid Build Coastguard Worker }
120*be431cd8SAndroid Build Coastguard Worker 
121*be431cd8SAndroid Build Coastguard Worker }  // namespace android
122