Loading media/audioaidlconversion/AidlConversionNdkCpp.cpp 0 → 100644 +128 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 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. */ #include <algorithm> #include <type_traits> #define LOG_TAG "AidlConversionNdkCpp" #include <utils/Log.h> #include <android-base/expected.h> #include <android/binder_auto_utils.h> #include <android/binder_enums.h> #include <android/binder_parcel.h> #include <binder/Enums.h> #include <media/AidlConversionNdkCpp.h> #include <media/AidlConversionUtil.h> using aidl::android::aidl_utils::statusTFromBinderStatusT; namespace android { namespace { // cpp2ndk and ndk2cpp are universal converters which work for any type, // however they are not the most efficient way to convert due to extra // marshaling / unmarshaling step. template<typename NdkType, typename CppType> ConversionResult<NdkType> cpp2ndk(const CppType& cpp) { Parcel cppParcel; RETURN_IF_ERROR(cpp.writeToParcel(&cppParcel)); ::ndk::ScopedAParcel ndkParcel(AParcel_create()); const int32_t ndkParcelBegin = AParcel_getDataPosition(ndkParcel.get()); RETURN_IF_ERROR(statusTFromBinderStatusT(AParcel_unmarshal( ndkParcel.get(), cppParcel.data(), cppParcel.dataSize()))); RETURN_IF_ERROR(statusTFromBinderStatusT(AParcel_setDataPosition( ndkParcel.get(), ndkParcelBegin))); NdkType ndk; RETURN_IF_ERROR(statusTFromBinderStatusT(ndk.readFromParcel(ndkParcel.get()))); return ndk; } template<typename CppType, typename NdkType> ConversionResult<CppType> ndk2cpp(const NdkType& ndk) { ::ndk::ScopedAParcel ndkParcel(AParcel_create()); RETURN_IF_ERROR(statusTFromBinderStatusT(ndk.writeToParcel(ndkParcel.get()))); const int32_t ndkParcelDataSize = AParcel_getDataSize(ndkParcel.get()); if (ndkParcelDataSize < 0) { return base::unexpected(BAD_VALUE); } // Parcel does not expose its data in a mutable form, we have to use an intermediate buffer. std::vector<uint8_t> parcelData(static_cast<size_t>(ndkParcelDataSize)); RETURN_IF_ERROR(statusTFromBinderStatusT(AParcel_marshal( ndkParcel.get(), parcelData.data(), 0, ndkParcelDataSize))); Parcel cppParcel; RETURN_IF_ERROR(cppParcel.setData(parcelData.data(), parcelData.size())); CppType cpp; RETURN_IF_ERROR(cpp.readFromParcel(&cppParcel)); return cpp; } // cpp2ndk_Enum and ndk2cpp_Enum are more efficient implementations specifically for enums. template<typename OutEnum, typename OutEnumRange, typename InEnum> ConversionResult<OutEnum> convertEnum(const OutEnumRange& range, InEnum e) { using InIntType = std::underlying_type_t<InEnum>; static_assert(std::is_same_v<InIntType, std::underlying_type_t<OutEnum>>); InIntType inEnumIndex = static_cast<InIntType>(e); OutEnum outEnum = static_cast<OutEnum>(inEnumIndex); if (std::find(range.begin(), range.end(), outEnum) == range.end()) { return base::unexpected(BAD_VALUE); } return outEnum; } template<typename NdkEnum, typename CppEnum> ConversionResult<NdkEnum> cpp2ndk_Enum(CppEnum cpp) { return convertEnum<NdkEnum>(::ndk::enum_range<NdkEnum>(), cpp); } template<typename CppEnum, typename NdkEnum> ConversionResult<CppEnum> ndk2cpp_Enum(NdkEnum ndk) { return convertEnum<CppEnum>(enum_range<CppEnum>(), ndk); } } // namespace #define GENERATE_CONVERTERS(packageName, className) \ ConversionResult<::aidl::packageName::className> cpp2ndk_##className( \ const ::packageName::className& cpp) { \ return cpp2ndk<::aidl::packageName::className>(cpp); \ } \ ConversionResult<::packageName::className> ndk2cpp_##className( \ const ::aidl::packageName::className& ndk) { \ return ndk2cpp<::packageName::className>(ndk); \ } #define GENERATE_ENUM_CONVERTERS(packageName, className) \ ConversionResult<::aidl::packageName::className> cpp2ndk_##className( \ const ::packageName::className& cpp) { \ return cpp2ndk_Enum<::aidl::packageName::className>(cpp); \ } \ ConversionResult<::packageName::className> ndk2cpp_##className( \ const ::aidl::packageName::className& ndk) { \ return ndk2cpp_Enum<::packageName::className>(ndk); \ } GENERATE_CONVERTERS(android::media::audio::common, AudioFormatDescription); GENERATE_CONVERTERS(android::media::audio::common, AudioHalEngineConfig); GENERATE_CONVERTERS(android::media::audio::common, AudioMMapPolicyInfo); GENERATE_ENUM_CONVERTERS(android::media::audio::common, AudioMMapPolicyType); GENERATE_CONVERTERS(android::media::audio::common, AudioPort); } // namespace android media/audioaidlconversion/Android.bp +24 −0 Original line number Diff line number Diff line Loading @@ -212,3 +212,27 @@ cc_library { ], min_sdk_version: "31", //AParcelableHolder has been introduced in 31 } /** * Conversions between the NDK and CPP backends for common types. */ cc_library { name: "libaudio_aidl_conversion_common_ndk_cpp", srcs: [ "AidlConversionNdkCpp.cpp", ], defaults: [ "audio_aidl_conversion_common_default", "audio_aidl_conversion_common_util_default", "latest_android_media_audio_common_types_cpp_shared", "latest_android_media_audio_common_types_ndk_shared", ], shared_libs: [ "libbinder_ndk", "libbase", ], cflags: [ "-DBACKEND_CPP_NDK", ], min_sdk_version: "33", //AParcel_unmarshal has been introduced in 33 } media/audioaidlconversion/TEST_MAPPING +2 −1 Original line number Diff line number Diff line { "presubmit": [ { "name": "audio_aidl_ndk_conversion_tests" "name": "audio_aidl_ndk_conversion_tests", "name": "audio_aidl_ndk_cpp_conversion_tests" } ] } media/audioaidlconversion/include/media/AidlConversionNdkCpp.h 0 → 100644 +50 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 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 /** * Conversions between the NDK and CPP backends for common types. */ #include <aidl/android/media/audio/common/AudioFormatDescription.h> #include <aidl/android/media/audio/common/AudioHalEngineConfig.h> #include <aidl/android/media/audio/common/AudioMMapPolicyInfo.h> #include <aidl/android/media/audio/common/AudioMMapPolicyType.h> #include <aidl/android/media/audio/common/AudioPort.h> #include <android/media/audio/common/AudioFormatDescription.h> #include <android/media/audio/common/AudioHalEngineConfig.h> #include <android/media/audio/common/AudioMMapPolicyInfo.h> #include <android/media/audio/common/AudioMMapPolicyType.h> #include <android/media/audio/common/AudioPort.h> #include <media/AidlConversionUtil.h> namespace android { #define DECLARE_CONVERTERS(packageName, className) \ ConversionResult<::aidl::packageName::className> \ cpp2ndk_##className(const ::packageName::className& cpp); \ ConversionResult<::packageName::className> \ ndk2cpp_##className(const ::aidl::packageName::className& ndk); DECLARE_CONVERTERS(android::media::audio::common, AudioFormatDescription); DECLARE_CONVERTERS(android::media::audio::common, AudioHalEngineConfig); DECLARE_CONVERTERS(android::media::audio::common, AudioMMapPolicyInfo); DECLARE_CONVERTERS(android::media::audio::common, AudioMMapPolicyType); DECLARE_CONVERTERS(android::media::audio::common, AudioPort); #undef DECLARE_CONVERTERS } // namespace android media/audioaidlconversion/include/media/AidlConversionUtil-impl.h +4 −0 Original line number Diff line number Diff line Loading @@ -389,6 +389,10 @@ static inline ::android::status_t statusTFromBinderStatus(const ::ndk::ScopedASt ?: statusTFromExceptionCode(status.getExceptionCode()); // a service-side error with a // standard Java exception (fromExceptionCode) } static inline ::android::status_t statusTFromBinderStatusT(binder_status_t status) { return statusTFromBinderStatus(::ndk::ScopedAStatus::fromStatus(status)); } #endif /** Loading Loading
media/audioaidlconversion/AidlConversionNdkCpp.cpp 0 → 100644 +128 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 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. */ #include <algorithm> #include <type_traits> #define LOG_TAG "AidlConversionNdkCpp" #include <utils/Log.h> #include <android-base/expected.h> #include <android/binder_auto_utils.h> #include <android/binder_enums.h> #include <android/binder_parcel.h> #include <binder/Enums.h> #include <media/AidlConversionNdkCpp.h> #include <media/AidlConversionUtil.h> using aidl::android::aidl_utils::statusTFromBinderStatusT; namespace android { namespace { // cpp2ndk and ndk2cpp are universal converters which work for any type, // however they are not the most efficient way to convert due to extra // marshaling / unmarshaling step. template<typename NdkType, typename CppType> ConversionResult<NdkType> cpp2ndk(const CppType& cpp) { Parcel cppParcel; RETURN_IF_ERROR(cpp.writeToParcel(&cppParcel)); ::ndk::ScopedAParcel ndkParcel(AParcel_create()); const int32_t ndkParcelBegin = AParcel_getDataPosition(ndkParcel.get()); RETURN_IF_ERROR(statusTFromBinderStatusT(AParcel_unmarshal( ndkParcel.get(), cppParcel.data(), cppParcel.dataSize()))); RETURN_IF_ERROR(statusTFromBinderStatusT(AParcel_setDataPosition( ndkParcel.get(), ndkParcelBegin))); NdkType ndk; RETURN_IF_ERROR(statusTFromBinderStatusT(ndk.readFromParcel(ndkParcel.get()))); return ndk; } template<typename CppType, typename NdkType> ConversionResult<CppType> ndk2cpp(const NdkType& ndk) { ::ndk::ScopedAParcel ndkParcel(AParcel_create()); RETURN_IF_ERROR(statusTFromBinderStatusT(ndk.writeToParcel(ndkParcel.get()))); const int32_t ndkParcelDataSize = AParcel_getDataSize(ndkParcel.get()); if (ndkParcelDataSize < 0) { return base::unexpected(BAD_VALUE); } // Parcel does not expose its data in a mutable form, we have to use an intermediate buffer. std::vector<uint8_t> parcelData(static_cast<size_t>(ndkParcelDataSize)); RETURN_IF_ERROR(statusTFromBinderStatusT(AParcel_marshal( ndkParcel.get(), parcelData.data(), 0, ndkParcelDataSize))); Parcel cppParcel; RETURN_IF_ERROR(cppParcel.setData(parcelData.data(), parcelData.size())); CppType cpp; RETURN_IF_ERROR(cpp.readFromParcel(&cppParcel)); return cpp; } // cpp2ndk_Enum and ndk2cpp_Enum are more efficient implementations specifically for enums. template<typename OutEnum, typename OutEnumRange, typename InEnum> ConversionResult<OutEnum> convertEnum(const OutEnumRange& range, InEnum e) { using InIntType = std::underlying_type_t<InEnum>; static_assert(std::is_same_v<InIntType, std::underlying_type_t<OutEnum>>); InIntType inEnumIndex = static_cast<InIntType>(e); OutEnum outEnum = static_cast<OutEnum>(inEnumIndex); if (std::find(range.begin(), range.end(), outEnum) == range.end()) { return base::unexpected(BAD_VALUE); } return outEnum; } template<typename NdkEnum, typename CppEnum> ConversionResult<NdkEnum> cpp2ndk_Enum(CppEnum cpp) { return convertEnum<NdkEnum>(::ndk::enum_range<NdkEnum>(), cpp); } template<typename CppEnum, typename NdkEnum> ConversionResult<CppEnum> ndk2cpp_Enum(NdkEnum ndk) { return convertEnum<CppEnum>(enum_range<CppEnum>(), ndk); } } // namespace #define GENERATE_CONVERTERS(packageName, className) \ ConversionResult<::aidl::packageName::className> cpp2ndk_##className( \ const ::packageName::className& cpp) { \ return cpp2ndk<::aidl::packageName::className>(cpp); \ } \ ConversionResult<::packageName::className> ndk2cpp_##className( \ const ::aidl::packageName::className& ndk) { \ return ndk2cpp<::packageName::className>(ndk); \ } #define GENERATE_ENUM_CONVERTERS(packageName, className) \ ConversionResult<::aidl::packageName::className> cpp2ndk_##className( \ const ::packageName::className& cpp) { \ return cpp2ndk_Enum<::aidl::packageName::className>(cpp); \ } \ ConversionResult<::packageName::className> ndk2cpp_##className( \ const ::aidl::packageName::className& ndk) { \ return ndk2cpp_Enum<::packageName::className>(ndk); \ } GENERATE_CONVERTERS(android::media::audio::common, AudioFormatDescription); GENERATE_CONVERTERS(android::media::audio::common, AudioHalEngineConfig); GENERATE_CONVERTERS(android::media::audio::common, AudioMMapPolicyInfo); GENERATE_ENUM_CONVERTERS(android::media::audio::common, AudioMMapPolicyType); GENERATE_CONVERTERS(android::media::audio::common, AudioPort); } // namespace android
media/audioaidlconversion/Android.bp +24 −0 Original line number Diff line number Diff line Loading @@ -212,3 +212,27 @@ cc_library { ], min_sdk_version: "31", //AParcelableHolder has been introduced in 31 } /** * Conversions between the NDK and CPP backends for common types. */ cc_library { name: "libaudio_aidl_conversion_common_ndk_cpp", srcs: [ "AidlConversionNdkCpp.cpp", ], defaults: [ "audio_aidl_conversion_common_default", "audio_aidl_conversion_common_util_default", "latest_android_media_audio_common_types_cpp_shared", "latest_android_media_audio_common_types_ndk_shared", ], shared_libs: [ "libbinder_ndk", "libbase", ], cflags: [ "-DBACKEND_CPP_NDK", ], min_sdk_version: "33", //AParcel_unmarshal has been introduced in 33 }
media/audioaidlconversion/TEST_MAPPING +2 −1 Original line number Diff line number Diff line { "presubmit": [ { "name": "audio_aidl_ndk_conversion_tests" "name": "audio_aidl_ndk_conversion_tests", "name": "audio_aidl_ndk_cpp_conversion_tests" } ] }
media/audioaidlconversion/include/media/AidlConversionNdkCpp.h 0 → 100644 +50 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 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 /** * Conversions between the NDK and CPP backends for common types. */ #include <aidl/android/media/audio/common/AudioFormatDescription.h> #include <aidl/android/media/audio/common/AudioHalEngineConfig.h> #include <aidl/android/media/audio/common/AudioMMapPolicyInfo.h> #include <aidl/android/media/audio/common/AudioMMapPolicyType.h> #include <aidl/android/media/audio/common/AudioPort.h> #include <android/media/audio/common/AudioFormatDescription.h> #include <android/media/audio/common/AudioHalEngineConfig.h> #include <android/media/audio/common/AudioMMapPolicyInfo.h> #include <android/media/audio/common/AudioMMapPolicyType.h> #include <android/media/audio/common/AudioPort.h> #include <media/AidlConversionUtil.h> namespace android { #define DECLARE_CONVERTERS(packageName, className) \ ConversionResult<::aidl::packageName::className> \ cpp2ndk_##className(const ::packageName::className& cpp); \ ConversionResult<::packageName::className> \ ndk2cpp_##className(const ::aidl::packageName::className& ndk); DECLARE_CONVERTERS(android::media::audio::common, AudioFormatDescription); DECLARE_CONVERTERS(android::media::audio::common, AudioHalEngineConfig); DECLARE_CONVERTERS(android::media::audio::common, AudioMMapPolicyInfo); DECLARE_CONVERTERS(android::media::audio::common, AudioMMapPolicyType); DECLARE_CONVERTERS(android::media::audio::common, AudioPort); #undef DECLARE_CONVERTERS } // namespace android
media/audioaidlconversion/include/media/AidlConversionUtil-impl.h +4 −0 Original line number Diff line number Diff line Loading @@ -389,6 +389,10 @@ static inline ::android::status_t statusTFromBinderStatus(const ::ndk::ScopedASt ?: statusTFromExceptionCode(status.getExceptionCode()); // a service-side error with a // standard Java exception (fromExceptionCode) } static inline ::android::status_t statusTFromBinderStatusT(binder_status_t status) { return statusTFromBinderStatus(::ndk::ScopedAStatus::fromStatus(status)); } #endif /** Loading