blob: ecd2e5ec12c987f8fdf77228d037a89e6e66aa55 [file] [log] [blame]
Mikhail Naganovbfbb75b2023-04-21 18:48:16 -07001/*
2 * Copyright (C) 2023 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#include <algorithm>
Mikhail Naganov1c400902023-05-17 11:48:43 -070018#include <regex>
Mikhail Naganovbfbb75b2023-04-21 18:48:16 -070019#include <type_traits>
20
21#define LOG_TAG "AidlConversionNdkCpp"
22#include <utils/Log.h>
23
24#include <android-base/expected.h>
25#include <android/binder_auto_utils.h>
26#include <android/binder_enums.h>
27#include <android/binder_parcel.h>
28#include <binder/Enums.h>
29#include <media/AidlConversionNdkCpp.h>
30#include <media/AidlConversionUtil.h>
31
32using aidl::android::aidl_utils::statusTFromBinderStatusT;
33
34namespace android {
35
36namespace {
37
Mikhail Naganov1c400902023-05-17 11:48:43 -070038bool isVendorExtension(const std::string& s) {
39 // Per definition in AudioAttributes.aidl and {Playback|Record}TrackMetadata.aidl
40 static const std::regex vendorExtension("VX_[A-Z0-9]{3,}_[_A-Z0-9]+");
41 return std::regex_match(s.begin(), s.end(), vendorExtension);
42}
43
44inline bool isNotVendorExtension(const std::string& s) { return !isVendorExtension(s); }
45
46void filterOutNonVendorTagsInPlace(std::vector<std::string>& tags) {
47 if (std::find_if(tags.begin(), tags.end(), isNotVendorExtension) == tags.end()) {
48 return;
49 }
50 std::vector<std::string> temp;
51 temp.reserve(tags.size());
52 std::copy_if(tags.begin(), tags.end(), std::back_inserter(temp), isVendorExtension);
53 tags = std::move(temp);
54}
55
Mikhail Naganovbfbb75b2023-04-21 18:48:16 -070056// cpp2ndk and ndk2cpp are universal converters which work for any type,
57// however they are not the most efficient way to convert due to extra
58// marshaling / unmarshaling step.
59
60template<typename NdkType, typename CppType>
61ConversionResult<NdkType> cpp2ndk(const CppType& cpp) {
62 Parcel cppParcel;
63 RETURN_IF_ERROR(cpp.writeToParcel(&cppParcel));
64 ::ndk::ScopedAParcel ndkParcel(AParcel_create());
65 const int32_t ndkParcelBegin = AParcel_getDataPosition(ndkParcel.get());
66 RETURN_IF_ERROR(statusTFromBinderStatusT(AParcel_unmarshal(
67 ndkParcel.get(), cppParcel.data(), cppParcel.dataSize())));
68 RETURN_IF_ERROR(statusTFromBinderStatusT(AParcel_setDataPosition(
69 ndkParcel.get(), ndkParcelBegin)));
70 NdkType ndk;
71 RETURN_IF_ERROR(statusTFromBinderStatusT(ndk.readFromParcel(ndkParcel.get())));
72 return ndk;
73}
74
75template<typename CppType, typename NdkType>
76ConversionResult<CppType> ndk2cpp(const NdkType& ndk) {
77 ::ndk::ScopedAParcel ndkParcel(AParcel_create());
78 RETURN_IF_ERROR(statusTFromBinderStatusT(ndk.writeToParcel(ndkParcel.get())));
79 const int32_t ndkParcelDataSize = AParcel_getDataSize(ndkParcel.get());
80 if (ndkParcelDataSize < 0) {
81 return base::unexpected(BAD_VALUE);
82 }
83 // Parcel does not expose its data in a mutable form, we have to use an intermediate buffer.
84 std::vector<uint8_t> parcelData(static_cast<size_t>(ndkParcelDataSize));
85 RETURN_IF_ERROR(statusTFromBinderStatusT(AParcel_marshal(
86 ndkParcel.get(), parcelData.data(), 0, ndkParcelDataSize)));
87 Parcel cppParcel;
88 RETURN_IF_ERROR(cppParcel.setData(parcelData.data(), parcelData.size()));
89 CppType cpp;
90 RETURN_IF_ERROR(cpp.readFromParcel(&cppParcel));
91 return cpp;
92}
93
94// cpp2ndk_Enum and ndk2cpp_Enum are more efficient implementations specifically for enums.
95
96template<typename OutEnum, typename OutEnumRange, typename InEnum>
97 ConversionResult<OutEnum> convertEnum(const OutEnumRange& range, InEnum e) {
98 using InIntType = std::underlying_type_t<InEnum>;
99 static_assert(std::is_same_v<InIntType, std::underlying_type_t<OutEnum>>);
100
101 InIntType inEnumIndex = static_cast<InIntType>(e);
102 OutEnum outEnum = static_cast<OutEnum>(inEnumIndex);
103 if (std::find(range.begin(), range.end(), outEnum) == range.end()) {
104 return base::unexpected(BAD_VALUE);
105 }
106 return outEnum;
107}
108
109template<typename NdkEnum, typename CppEnum>
110 ConversionResult<NdkEnum> cpp2ndk_Enum(CppEnum cpp) {
111 return convertEnum<NdkEnum>(::ndk::enum_range<NdkEnum>(), cpp);
112}
113
114template<typename CppEnum, typename NdkEnum>
115 ConversionResult<CppEnum> ndk2cpp_Enum(NdkEnum ndk) {
116 return convertEnum<CppEnum>(enum_range<CppEnum>(), ndk);
117}
118
119} // namespace
120
Mikhail Naganov1c400902023-05-17 11:48:43 -0700121#define GENERATE_CONVERTERS(packageName, className) \
122 GENERATE_CONVERTERS_IMPL(packageName, _, className)
123
124#define GENERATE_CONVERTERS_IMPL(packageName, prefix, className) \
125 ConversionResult<::aidl::packageName::className> cpp2ndk##prefix##className( \
Mikhail Naganovbfbb75b2023-04-21 18:48:16 -0700126 const ::packageName::className& cpp) { \
127 return cpp2ndk<::aidl::packageName::className>(cpp); \
128 } \
Mikhail Naganov1c400902023-05-17 11:48:43 -0700129 ConversionResult<::packageName::className> ndk2cpp##prefix##className( \
Mikhail Naganovbfbb75b2023-04-21 18:48:16 -0700130 const ::aidl::packageName::className& ndk) { \
131 return ndk2cpp<::packageName::className>(ndk); \
132 }
133
134#define GENERATE_ENUM_CONVERTERS(packageName, className) \
135 ConversionResult<::aidl::packageName::className> cpp2ndk_##className( \
136 const ::packageName::className& cpp) { \
137 return cpp2ndk_Enum<::aidl::packageName::className>(cpp); \
138 } \
139 ConversionResult<::packageName::className> ndk2cpp_##className( \
140 const ::aidl::packageName::className& ndk) { \
141 return ndk2cpp_Enum<::packageName::className>(ndk); \
142}
143
144GENERATE_CONVERTERS(android::media::audio::common, AudioFormatDescription);
Mikhail Naganov1c400902023-05-17 11:48:43 -0700145GENERATE_CONVERTERS_IMPL(android::media::audio::common, _Impl_, AudioHalEngineConfig);
Mikhail Naganovbfbb75b2023-04-21 18:48:16 -0700146GENERATE_CONVERTERS(android::media::audio::common, AudioMMapPolicyInfo);
147GENERATE_ENUM_CONVERTERS(android::media::audio::common, AudioMMapPolicyType);
Mikhail Naganovffd97712023-05-03 17:45:36 -0700148GENERATE_ENUM_CONVERTERS(android::media::audio::common, AudioMode);
Mikhail Naganovbfbb75b2023-04-21 18:48:16 -0700149GENERATE_CONVERTERS(android::media::audio::common, AudioPort);
150
Mikhail Naganov1c400902023-05-17 11:48:43 -0700151namespace {
152
153// Filter out all AudioAttributes tags that do not conform to the vendor extension pattern.
154template<typename T>
155void filterOutNonVendorTags(T& audioHalEngineConfig) {
156 for (auto& strategy : audioHalEngineConfig.productStrategies) {
157 for (auto& group : strategy.attributesGroups) {
158 for (auto& attr : group.attributes) {
159 filterOutNonVendorTagsInPlace(attr.tags);
160 }
161 }
162 }
163}
164
165} // namespace
166
167ConversionResult<::aidl::android::media::audio::common::AudioHalEngineConfig>
168cpp2ndk_AudioHalEngineConfig(const ::android::media::audio::common::AudioHalEngineConfig& cpp) {
169 auto conv = cpp2ndk_Impl_AudioHalEngineConfig(cpp);
170 if (conv.ok()) {
171 filterOutNonVendorTags(conv.value());
172 }
173 return conv;
174}
175
176ConversionResult<::android::media::audio::common::AudioHalEngineConfig>
177ndk2cpp_AudioHalEngineConfig(
178 const ::aidl::android::media::audio::common::AudioHalEngineConfig& ndk) {
179 auto conv = ndk2cpp_Impl_AudioHalEngineConfig(ndk);
180 if (conv.ok()) {
181 filterOutNonVendorTags(conv.value());
182 }
183 return conv;
184}
185
186
Mikhail Naganovbfbb75b2023-04-21 18:48:16 -0700187} // namespace android