diff options
| author | 2021-02-04 10:18:37 +0900 | |
|---|---|---|
| committer | 2021-02-04 15:17:01 +0900 | |
| commit | caede598ee66bdda3c69706eed75d39fe9fdecca (patch) | |
| tree | 1eada2b1de06f33033f26ac4d2fc7e033c13e2ac | |
| parent | 07278cc954a2f7ebb71130b18b0d3668302c843f (diff) | |
Add a shared header lib for libbinder/libbinder_ndk
The new header lib will be shared by libbinder and libbinder_ndk.
We'll put shared functionality here.
For now, it contains ToString() which is used by AIDL-generated
parcelables for both C++ and NDK backends.
Bug: 179020493
Test: aidl_integration_test
Change-Id: I930a334fa6d6f1a7b38729f8df6bcdb202c9f19c
| -rw-r--r-- | libs/binder/Android.bp | 2 | ||||
| -rw-r--r-- | libs/binder/ndk/Android.bp | 22 | ||||
| -rw-r--r-- | libs/binder/ndk/include_cpp/android/binder_to_string.h | 184 |
3 files changed, 208 insertions, 0 deletions
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index ed079db4b3..11b032b687 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -22,11 +22,13 @@ cc_library_headers { header_libs: [ "libbase_headers", + "libbinder_headers_platform_shared", "libcutils_headers", "libutils_headers", ], export_header_lib_headers: [ "libbase_headers", + "libbinder_headers_platform_shared", "libcutils_headers", "libutils_headers", ], diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp index 82f388284c..d76a1f90e8 100644 --- a/libs/binder/ndk/Android.bp +++ b/libs/binder/ndk/Android.bp @@ -129,6 +129,28 @@ cc_library { ], } +cc_library_headers { + name: "libbinder_headers_platform_shared", + export_include_dirs: ["include_cpp"], + vendor_available: true, + host_supported: true, + // TODO(b/153609531): remove when no longer needed. + native_bridge_supported: true, + target: { + darwin: { + enabled: false, + }, + }, + min_sdk_version: "29", + apex_available: [ + "//apex_available:platform", + // TODO(b/166468760) remove these three + "com.android.media", + "com.android.media.swcodec", + "test_com.android.media.swcodec", + ], +} + ndk_headers { name: "libbinder_ndk_headers", from: "include_ndk/android", diff --git a/libs/binder/ndk/include_cpp/android/binder_to_string.h b/libs/binder/ndk/include_cpp/android/binder_to_string.h new file mode 100644 index 0000000000..bd51b1167f --- /dev/null +++ b/libs/binder/ndk/include_cpp/android/binder_to_string.h @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2021 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. + */ + +/** + * @addtogroup NdkBinder + * @{ + */ + +/** + * @file binder_to_string.h + * @brief Helper for parcelable. + */ + +#pragma once + +#include <codecvt> +#include <locale> +#include <sstream> +#include <string> +#include <type_traits> + +#if __has_include(<android/binder_ibinder.h>) +#include <android/binder_auto_utils.h> +#include <android/binder_interface_utils.h> +#include <android/binder_parcelable_utils.h> +#define HAS_NDK_INTERFACE +#else +#include <binder/IBinder.h> +#include <binder/IInterface.h> +#include <binder/ParcelFileDescriptor.h> +#include <binder/ParcelableHolder.h> +#include <utils/String16.h> +#include <utils/StrongPointer.h> +#define HAS_CPP_INTERFACE +#endif //_has_include + +namespace android { +namespace internal { + +// ToString is a utility to generate string representation for various AIDL-supported types. +template <typename _T> +std::string ToString(const _T& t); + +namespace details { + +// Truthy if _T has toString() method. +template <typename _T> +class HasToStringMethod { + template <typename _U> + static auto _test(int) -> decltype(std::declval<_U>().toString(), std::true_type()); + template <typename _U> + static std::false_type _test(...); + + public: + enum { value = decltype(_test<_T>(0))::value }; +}; + +// Truthy if _T has a overloaded toString(T) +template <typename _T> +class HasToStringFunction { + template <typename _U> + static auto _test(int) -> decltype(toString(std::declval<_U>()), std::true_type()); + template <typename _U> + static std::false_type _test(...); + + public: + enum { value = decltype(_test<_T>(0))::value }; +}; + +// Truthy if _T is like a pointer +template <typename _T> +class IsPointerLike { + template <typename _U> + static auto _test(int) -> decltype(!std::declval<_U>(), *std::declval<_U>(), std::true_type()); + template <typename _U> + static std::false_type _test(...); + + public: + enum { value = decltype(_test<_T>(0))::value }; +}; + +// Truthy if _T is like a container +template <typename _T> +class IsIterable { + template <typename _U> + static auto _test(int) + -> decltype(begin(std::declval<_U>()), end(std::declval<_U>()), std::true_type()); + template <typename _U> + static std::false_type _test(...); + + public: + enum { value = decltype(_test<_T>(0))::value }; +}; + +template <typename _T> +class ToEmptyString { + template <typename _U> + static std::enable_if_t< +#ifdef HAS_NDK_INTERFACE + std::is_base_of_v<::ndk::ICInterface, _U> || std::is_same_v<::ndk::SpAIBinder, _U> || + std::is_same_v<::ndk::ScopedFileDescriptor, _U> || + std::is_same_v<::ndk::AParcelableHolder, _U> +#else + std::is_base_of_v<IInterface, _U> || std::is_same_v<IBinder, _U> || + std::is_same_v<os::ParcelFileDescriptor, _U> || + std::is_same_v<os::ParcelableHolder, _U> +#endif + , + std::true_type> + _test(int); + template <typename _U> + static std::false_type _test(...); + + public: + enum { value = decltype(_test<_T>(0))::value }; +}; + +} // namespace details + +template <typename _T> +std::string ToString(const _T& t) { + if constexpr (details::ToEmptyString<_T>::value) { + return ""; + } else if constexpr (std::is_same_v<bool, _T>) { + return t ? "true" : "false"; + } else if constexpr (std::is_same_v<char16_t, _T>) { + return std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>().to_bytes(t); + } else if constexpr (std::is_arithmetic_v<_T>) { + return std::to_string(t); + } else if constexpr (std::is_same_v<std::string, _T>) { + return t; +#ifdef HAS_CPP_INTERFACE + } else if constexpr (std::is_same_v<String16, _T>) { + std::stringstream out; + out << t; + return out.str(); +#endif + } else if constexpr (details::HasToStringMethod<_T>::value) { + return t.toString(); + } else if constexpr (details::HasToStringFunction<_T>::value) { + return toString(t); + } else if constexpr (details::IsIterable<_T>::value) { + std::stringstream out; + bool first = true; + out << "["; + for (const auto& e : t) { + if (first) { + first = false; + } else { + out << ", "; + } + // Use explicit type parameter in case deref of iterator has different type + // e.g. vector<bool> + out << ToString<typename _T::value_type>(e); + } + out << "]"; + return out.str(); + } else if constexpr (details::IsPointerLike<_T>::value) { + if (!t) return "(null)"; + std::stringstream out; + out << ToString(*t); + return out.str(); + } else { + return "{no toString() implemented}"; + } +} + +} // namespace internal +} // namespace android + +/** @} */ |