1*ec779b8eSAndroid Build Coastguard Worker /*
2*ec779b8eSAndroid Build Coastguard Worker * Copyright (C) 2023 The Android Open Source Project
3*ec779b8eSAndroid Build Coastguard Worker *
4*ec779b8eSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*ec779b8eSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*ec779b8eSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*ec779b8eSAndroid Build Coastguard Worker *
8*ec779b8eSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*ec779b8eSAndroid Build Coastguard Worker *
10*ec779b8eSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*ec779b8eSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*ec779b8eSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*ec779b8eSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*ec779b8eSAndroid Build Coastguard Worker * limitations under the License.
15*ec779b8eSAndroid Build Coastguard Worker */
16*ec779b8eSAndroid Build Coastguard Worker
17*ec779b8eSAndroid Build Coastguard Worker #include <algorithm>
18*ec779b8eSAndroid Build Coastguard Worker #include <regex>
19*ec779b8eSAndroid Build Coastguard Worker #include <type_traits>
20*ec779b8eSAndroid Build Coastguard Worker
21*ec779b8eSAndroid Build Coastguard Worker #define LOG_TAG "AidlConversionNdkCpp"
22*ec779b8eSAndroid Build Coastguard Worker #include <utils/Log.h>
23*ec779b8eSAndroid Build Coastguard Worker
24*ec779b8eSAndroid Build Coastguard Worker #include <android-base/expected.h>
25*ec779b8eSAndroid Build Coastguard Worker #include <android/binder_auto_utils.h>
26*ec779b8eSAndroid Build Coastguard Worker #include <android/binder_enums.h>
27*ec779b8eSAndroid Build Coastguard Worker #include <android/binder_parcel.h>
28*ec779b8eSAndroid Build Coastguard Worker #include <binder/Enums.h>
29*ec779b8eSAndroid Build Coastguard Worker #include <media/AidlConversionNdkCpp.h>
30*ec779b8eSAndroid Build Coastguard Worker #include <media/AidlConversionUtil.h>
31*ec779b8eSAndroid Build Coastguard Worker
32*ec779b8eSAndroid Build Coastguard Worker using aidl::android::aidl_utils::statusTFromBinderStatusT;
33*ec779b8eSAndroid Build Coastguard Worker
34*ec779b8eSAndroid Build Coastguard Worker namespace android {
35*ec779b8eSAndroid Build Coastguard Worker
36*ec779b8eSAndroid Build Coastguard Worker namespace {
37*ec779b8eSAndroid Build Coastguard Worker
isVendorExtension(const std::string & s)38*ec779b8eSAndroid Build Coastguard Worker bool isVendorExtension(const std::string& s) {
39*ec779b8eSAndroid Build Coastguard Worker // Per definition in AudioAttributes.aidl and {Playback|Record}TrackMetadata.aidl
40*ec779b8eSAndroid Build Coastguard Worker static const std::regex vendorExtension("VX_[A-Z0-9]{3,}_[_A-Z0-9]+");
41*ec779b8eSAndroid Build Coastguard Worker return std::regex_match(s.begin(), s.end(), vendorExtension);
42*ec779b8eSAndroid Build Coastguard Worker }
43*ec779b8eSAndroid Build Coastguard Worker
isNotVendorExtension(const std::string & s)44*ec779b8eSAndroid Build Coastguard Worker inline bool isNotVendorExtension(const std::string& s) { return !isVendorExtension(s); }
45*ec779b8eSAndroid Build Coastguard Worker
filterOutNonVendorTagsInPlace(std::vector<std::string> & tags)46*ec779b8eSAndroid Build Coastguard Worker void filterOutNonVendorTagsInPlace(std::vector<std::string>& tags) {
47*ec779b8eSAndroid Build Coastguard Worker if (std::find_if(tags.begin(), tags.end(), isNotVendorExtension) == tags.end()) {
48*ec779b8eSAndroid Build Coastguard Worker return;
49*ec779b8eSAndroid Build Coastguard Worker }
50*ec779b8eSAndroid Build Coastguard Worker std::vector<std::string> temp;
51*ec779b8eSAndroid Build Coastguard Worker temp.reserve(tags.size());
52*ec779b8eSAndroid Build Coastguard Worker std::copy_if(tags.begin(), tags.end(), std::back_inserter(temp), isVendorExtension);
53*ec779b8eSAndroid Build Coastguard Worker tags = std::move(temp);
54*ec779b8eSAndroid Build Coastguard Worker }
55*ec779b8eSAndroid Build Coastguard Worker
56*ec779b8eSAndroid Build Coastguard Worker // cpp2ndk and ndk2cpp are universal converters which work for any type,
57*ec779b8eSAndroid Build Coastguard Worker // however they are not the most efficient way to convert due to extra
58*ec779b8eSAndroid Build Coastguard Worker // marshaling / unmarshaling step.
59*ec779b8eSAndroid Build Coastguard Worker
60*ec779b8eSAndroid Build Coastguard Worker template<typename NdkType, typename CppType>
cpp2ndk(const CppType & cpp)61*ec779b8eSAndroid Build Coastguard Worker ConversionResult<NdkType> cpp2ndk(const CppType& cpp) {
62*ec779b8eSAndroid Build Coastguard Worker Parcel cppParcel;
63*ec779b8eSAndroid Build Coastguard Worker RETURN_IF_ERROR(cpp.writeToParcel(&cppParcel));
64*ec779b8eSAndroid Build Coastguard Worker ::ndk::ScopedAParcel ndkParcel(AParcel_create());
65*ec779b8eSAndroid Build Coastguard Worker const int32_t ndkParcelBegin = AParcel_getDataPosition(ndkParcel.get());
66*ec779b8eSAndroid Build Coastguard Worker RETURN_IF_ERROR(statusTFromBinderStatusT(AParcel_unmarshal(
67*ec779b8eSAndroid Build Coastguard Worker ndkParcel.get(), cppParcel.data(), cppParcel.dataSize())));
68*ec779b8eSAndroid Build Coastguard Worker RETURN_IF_ERROR(statusTFromBinderStatusT(AParcel_setDataPosition(
69*ec779b8eSAndroid Build Coastguard Worker ndkParcel.get(), ndkParcelBegin)));
70*ec779b8eSAndroid Build Coastguard Worker NdkType ndk;
71*ec779b8eSAndroid Build Coastguard Worker RETURN_IF_ERROR(statusTFromBinderStatusT(ndk.readFromParcel(ndkParcel.get())));
72*ec779b8eSAndroid Build Coastguard Worker return ndk;
73*ec779b8eSAndroid Build Coastguard Worker }
74*ec779b8eSAndroid Build Coastguard Worker
75*ec779b8eSAndroid Build Coastguard Worker template<typename CppType, typename NdkType>
ndk2cpp(const NdkType & ndk)76*ec779b8eSAndroid Build Coastguard Worker ConversionResult<CppType> ndk2cpp(const NdkType& ndk) {
77*ec779b8eSAndroid Build Coastguard Worker ::ndk::ScopedAParcel ndkParcel(AParcel_create());
78*ec779b8eSAndroid Build Coastguard Worker RETURN_IF_ERROR(statusTFromBinderStatusT(ndk.writeToParcel(ndkParcel.get())));
79*ec779b8eSAndroid Build Coastguard Worker const int32_t ndkParcelDataSize = AParcel_getDataSize(ndkParcel.get());
80*ec779b8eSAndroid Build Coastguard Worker if (ndkParcelDataSize < 0) {
81*ec779b8eSAndroid Build Coastguard Worker return base::unexpected(BAD_VALUE);
82*ec779b8eSAndroid Build Coastguard Worker }
83*ec779b8eSAndroid Build Coastguard Worker // Parcel does not expose its data in a mutable form, we have to use an intermediate buffer.
84*ec779b8eSAndroid Build Coastguard Worker std::vector<uint8_t> parcelData(static_cast<size_t>(ndkParcelDataSize));
85*ec779b8eSAndroid Build Coastguard Worker RETURN_IF_ERROR(statusTFromBinderStatusT(AParcel_marshal(
86*ec779b8eSAndroid Build Coastguard Worker ndkParcel.get(), parcelData.data(), 0, ndkParcelDataSize)));
87*ec779b8eSAndroid Build Coastguard Worker Parcel cppParcel;
88*ec779b8eSAndroid Build Coastguard Worker RETURN_IF_ERROR(cppParcel.setData(parcelData.data(), parcelData.size()));
89*ec779b8eSAndroid Build Coastguard Worker CppType cpp;
90*ec779b8eSAndroid Build Coastguard Worker RETURN_IF_ERROR(cpp.readFromParcel(&cppParcel));
91*ec779b8eSAndroid Build Coastguard Worker return cpp;
92*ec779b8eSAndroid Build Coastguard Worker }
93*ec779b8eSAndroid Build Coastguard Worker
94*ec779b8eSAndroid Build Coastguard Worker // cpp2ndk_Enum and ndk2cpp_Enum are more efficient implementations specifically for enums.
95*ec779b8eSAndroid Build Coastguard Worker
96*ec779b8eSAndroid Build Coastguard Worker template<typename OutEnum, typename OutEnumRange, typename InEnum>
convertEnum(const OutEnumRange & range,InEnum e)97*ec779b8eSAndroid Build Coastguard Worker ConversionResult<OutEnum> convertEnum(const OutEnumRange& range, InEnum e) {
98*ec779b8eSAndroid Build Coastguard Worker using InIntType = std::underlying_type_t<InEnum>;
99*ec779b8eSAndroid Build Coastguard Worker static_assert(std::is_same_v<InIntType, std::underlying_type_t<OutEnum>>);
100*ec779b8eSAndroid Build Coastguard Worker
101*ec779b8eSAndroid Build Coastguard Worker InIntType inEnumIndex = static_cast<InIntType>(e);
102*ec779b8eSAndroid Build Coastguard Worker OutEnum outEnum = static_cast<OutEnum>(inEnumIndex);
103*ec779b8eSAndroid Build Coastguard Worker if (std::find(range.begin(), range.end(), outEnum) == range.end()) {
104*ec779b8eSAndroid Build Coastguard Worker return base::unexpected(BAD_VALUE);
105*ec779b8eSAndroid Build Coastguard Worker }
106*ec779b8eSAndroid Build Coastguard Worker return outEnum;
107*ec779b8eSAndroid Build Coastguard Worker }
108*ec779b8eSAndroid Build Coastguard Worker
109*ec779b8eSAndroid Build Coastguard Worker template<typename NdkEnum, typename CppEnum>
cpp2ndk_Enum(CppEnum cpp)110*ec779b8eSAndroid Build Coastguard Worker ConversionResult<NdkEnum> cpp2ndk_Enum(CppEnum cpp) {
111*ec779b8eSAndroid Build Coastguard Worker return convertEnum<NdkEnum>(::ndk::enum_range<NdkEnum>(), cpp);
112*ec779b8eSAndroid Build Coastguard Worker }
113*ec779b8eSAndroid Build Coastguard Worker
114*ec779b8eSAndroid Build Coastguard Worker template<typename CppEnum, typename NdkEnum>
ndk2cpp_Enum(NdkEnum ndk)115*ec779b8eSAndroid Build Coastguard Worker ConversionResult<CppEnum> ndk2cpp_Enum(NdkEnum ndk) {
116*ec779b8eSAndroid Build Coastguard Worker return convertEnum<CppEnum>(enum_range<CppEnum>(), ndk);
117*ec779b8eSAndroid Build Coastguard Worker }
118*ec779b8eSAndroid Build Coastguard Worker
119*ec779b8eSAndroid Build Coastguard Worker } // namespace
120*ec779b8eSAndroid Build Coastguard Worker
121*ec779b8eSAndroid Build Coastguard Worker #define GENERATE_CONVERTERS(packageName, className) \
122*ec779b8eSAndroid Build Coastguard Worker GENERATE_CONVERTERS_IMPL(packageName, _, className)
123*ec779b8eSAndroid Build Coastguard Worker
124*ec779b8eSAndroid Build Coastguard Worker #define GENERATE_CONVERTERS_IMPL(packageName, prefix, className) \
125*ec779b8eSAndroid Build Coastguard Worker ConversionResult<::aidl::packageName::className> cpp2ndk##prefix##className( \
126*ec779b8eSAndroid Build Coastguard Worker const ::packageName::className& cpp) { \
127*ec779b8eSAndroid Build Coastguard Worker return cpp2ndk<::aidl::packageName::className>(cpp); \
128*ec779b8eSAndroid Build Coastguard Worker } \
129*ec779b8eSAndroid Build Coastguard Worker ConversionResult<::packageName::className> ndk2cpp##prefix##className( \
130*ec779b8eSAndroid Build Coastguard Worker const ::aidl::packageName::className& ndk) { \
131*ec779b8eSAndroid Build Coastguard Worker return ndk2cpp<::packageName::className>(ndk); \
132*ec779b8eSAndroid Build Coastguard Worker }
133*ec779b8eSAndroid Build Coastguard Worker
134*ec779b8eSAndroid Build Coastguard Worker #define GENERATE_ENUM_CONVERTERS(packageName, className) \
135*ec779b8eSAndroid Build Coastguard Worker ConversionResult<::aidl::packageName::className> cpp2ndk_##className( \
136*ec779b8eSAndroid Build Coastguard Worker const ::packageName::className& cpp) { \
137*ec779b8eSAndroid Build Coastguard Worker return cpp2ndk_Enum<::aidl::packageName::className>(cpp); \
138*ec779b8eSAndroid Build Coastguard Worker } \
139*ec779b8eSAndroid Build Coastguard Worker ConversionResult<::packageName::className> ndk2cpp_##className( \
140*ec779b8eSAndroid Build Coastguard Worker const ::aidl::packageName::className& ndk) { \
141*ec779b8eSAndroid Build Coastguard Worker return ndk2cpp_Enum<::packageName::className>(ndk); \
142*ec779b8eSAndroid Build Coastguard Worker }
143*ec779b8eSAndroid Build Coastguard Worker
144*ec779b8eSAndroid Build Coastguard Worker GENERATE_CONVERTERS(android::media::audio::common, AudioFormatDescription);
145*ec779b8eSAndroid Build Coastguard Worker GENERATE_CONVERTERS_IMPL(android::media::audio::common, _Impl_, AudioHalEngineConfig);
146*ec779b8eSAndroid Build Coastguard Worker GENERATE_CONVERTERS(android::media::audio::common, AudioMMapPolicyInfo);
147*ec779b8eSAndroid Build Coastguard Worker GENERATE_ENUM_CONVERTERS(android::media::audio::common, AudioMMapPolicyType);
148*ec779b8eSAndroid Build Coastguard Worker GENERATE_ENUM_CONVERTERS(android::media::audio::common, AudioMode);
149*ec779b8eSAndroid Build Coastguard Worker GENERATE_CONVERTERS(android::media::audio::common, AudioPort);
150*ec779b8eSAndroid Build Coastguard Worker
151*ec779b8eSAndroid Build Coastguard Worker namespace {
152*ec779b8eSAndroid Build Coastguard Worker
153*ec779b8eSAndroid Build Coastguard Worker // Filter out all AudioAttributes tags that do not conform to the vendor extension pattern.
154*ec779b8eSAndroid Build Coastguard Worker template<typename T>
filterOutNonVendorTags(T & audioHalEngineConfig)155*ec779b8eSAndroid Build Coastguard Worker void filterOutNonVendorTags(T& audioHalEngineConfig) {
156*ec779b8eSAndroid Build Coastguard Worker for (auto& strategy : audioHalEngineConfig.productStrategies) {
157*ec779b8eSAndroid Build Coastguard Worker for (auto& group : strategy.attributesGroups) {
158*ec779b8eSAndroid Build Coastguard Worker for (auto& attr : group.attributes) {
159*ec779b8eSAndroid Build Coastguard Worker filterOutNonVendorTagsInPlace(attr.tags);
160*ec779b8eSAndroid Build Coastguard Worker }
161*ec779b8eSAndroid Build Coastguard Worker }
162*ec779b8eSAndroid Build Coastguard Worker }
163*ec779b8eSAndroid Build Coastguard Worker }
164*ec779b8eSAndroid Build Coastguard Worker
165*ec779b8eSAndroid Build Coastguard Worker } // namespace
166*ec779b8eSAndroid Build Coastguard Worker
167*ec779b8eSAndroid Build Coastguard Worker ConversionResult<::aidl::android::media::audio::common::AudioHalEngineConfig>
cpp2ndk_AudioHalEngineConfig(const::android::media::audio::common::AudioHalEngineConfig & cpp)168*ec779b8eSAndroid Build Coastguard Worker cpp2ndk_AudioHalEngineConfig(const ::android::media::audio::common::AudioHalEngineConfig& cpp) {
169*ec779b8eSAndroid Build Coastguard Worker auto conv = cpp2ndk_Impl_AudioHalEngineConfig(cpp);
170*ec779b8eSAndroid Build Coastguard Worker if (conv.ok()) {
171*ec779b8eSAndroid Build Coastguard Worker filterOutNonVendorTags(conv.value());
172*ec779b8eSAndroid Build Coastguard Worker }
173*ec779b8eSAndroid Build Coastguard Worker return conv;
174*ec779b8eSAndroid Build Coastguard Worker }
175*ec779b8eSAndroid Build Coastguard Worker
176*ec779b8eSAndroid Build Coastguard Worker ConversionResult<::android::media::audio::common::AudioHalEngineConfig>
ndk2cpp_AudioHalEngineConfig(const::aidl::android::media::audio::common::AudioHalEngineConfig & ndk)177*ec779b8eSAndroid Build Coastguard Worker ndk2cpp_AudioHalEngineConfig(
178*ec779b8eSAndroid Build Coastguard Worker const ::aidl::android::media::audio::common::AudioHalEngineConfig& ndk) {
179*ec779b8eSAndroid Build Coastguard Worker auto conv = ndk2cpp_Impl_AudioHalEngineConfig(ndk);
180*ec779b8eSAndroid Build Coastguard Worker if (conv.ok()) {
181*ec779b8eSAndroid Build Coastguard Worker filterOutNonVendorTags(conv.value());
182*ec779b8eSAndroid Build Coastguard Worker }
183*ec779b8eSAndroid Build Coastguard Worker return conv;
184*ec779b8eSAndroid Build Coastguard Worker }
185*ec779b8eSAndroid Build Coastguard Worker
186*ec779b8eSAndroid Build Coastguard Worker
187*ec779b8eSAndroid Build Coastguard Worker } // namespace android
188