union support for NDK backend
Generated class for AIDL union for NDK backend is similar to the one for
C++ backend. Differences are
- not inheriting Parcelable, but has similar read/write methods
- not having comparison operators.
Bug: 150948558
Bug: 170784707
Test: aidl_unittests / aidl_integration_test
Test: CtsNdkBinderTestCases
Change-Id: Ib7f9265d7664ae98b9edd4a40d50351180c9a4d2
diff --git a/aidl_unittest.cpp b/aidl_unittest.cpp
index 3dd4e62..9dc2af0 100644
--- a/aidl_unittest.cpp
+++ b/aidl_unittest.cpp
@@ -2831,6 +2831,132 @@
} // namespace a
)";
+const char kUnionExampleExpectedOutputNdkHeader[] = R"(#pragma once
+#include <android/binder_interface_utils.h>
+#include <android/binder_parcelable_utils.h>
+
+#include <type_traits>
+#include <utility>
+#include <variant>
+#include <cstdint>
+#include <memory>
+#include <optional>
+#include <string>
+#include <vector>
+#ifdef BINDER_STABILITY_SUPPORT
+#include <android/binder_stability.h>
+#endif // BINDER_STABILITY_SUPPORT
+#include <aidl/a/ByteEnum.h>
+namespace aidl {
+namespace a {
+class Foo {
+public:
+ typedef std::false_type fixed_size;
+ static const char* descriptor;
+
+ enum Tag : int32_t {
+ ns = 0, // int[] ns;
+ e, // a.ByteEnum e;
+ };
+
+ template<typename _Tp>
+ static constexpr bool _not_self = !std::is_same_v<std::remove_cv_t<std::remove_reference_t<_Tp>>, Foo>;
+
+ Foo() : _value(std::in_place_index<ns>, std::vector<int32_t>({42})) { }
+ Foo(const Foo&) = default;
+ Foo(Foo&&) = default;
+ Foo& operator=(const Foo&) = default;
+ Foo& operator=(Foo&&) = default;
+
+ template <typename _Tp, std::enable_if_t<_not_self<_Tp>, int> = 0>
+ constexpr Foo(_Tp&& _arg)
+ : _value(std::forward<_Tp>(_arg)) {}
+
+ template <typename... _Tp>
+ constexpr explicit Foo(_Tp&&... _args)
+ : _value(std::forward<_Tp>(_args)...) {}
+
+ template <Tag _tag, typename... _Tp>
+ static Foo make(_Tp&&... _args) {
+ return Foo(std::in_place_index<_tag>, std::forward<_Tp>(_args)...);
+ }
+
+ template <Tag _tag, typename _Tp, typename... _Up>
+ static Foo make(std::initializer_list<_Tp> _il, _Up&&... _args) {
+ return Foo(std::in_place_index<_tag>, std::move(_il), std::forward<_Up>(_args)...);
+ }
+
+ Tag getTag() const {
+ return static_cast<Tag>(_value.index());
+ }
+
+ template <Tag _tag>
+ const auto& get() const {
+ if (getTag() != _tag) { abort(); }
+ return std::get<_tag>(_value);
+ }
+
+ template <Tag _tag>
+ auto& get() {
+ if (getTag() != _tag) { abort(); }
+ return std::get<_tag>(_value);
+ }
+
+ template <Tag _tag, typename... _Tp>
+ void set(_Tp&&... _args) {
+ _value.emplace<_tag>(std::forward<_Tp>(_args)...);
+ }
+
+ binder_status_t readFromParcel(const AParcel* _parcel);
+ binder_status_t writeToParcel(AParcel* _parcel) const;
+ static const ::ndk::parcelable_stability_t _aidl_stability = ::ndk::STABILITY_LOCAL;
+private:
+ std::variant<std::vector<int32_t>, ::aidl::a::ByteEnum> _value;
+};
+} // namespace a
+} // namespace aidl
+)";
+
+const char kUnionExampleExpectedOutputNdkSource[] = R"(#include "aidl/a/Foo.h"
+
+#include <android/binder_parcel_utils.h>
+
+namespace aidl {
+namespace a {
+const char* Foo::descriptor = "a.Foo";
+
+binder_status_t Foo::readFromParcel(const AParcel* _parcel) {
+ binder_status_t _aidl_ret_status;
+ int32_t _aidl_tag;
+ if ((_aidl_ret_status = AParcel_readInt32(_parcel, &_aidl_tag)) != STATUS_OK) return _aidl_ret_status;
+ switch (_aidl_tag) {
+ case ns: {
+ std::vector<int32_t> _aidl_value;
+ if ((_aidl_ret_status = ::ndk::AParcel_readVector(_parcel, &_aidl_value)) != STATUS_OK) return _aidl_ret_status;
+ set<ns>(std::move(_aidl_value));
+ return STATUS_OK; }
+ case e: {
+ ::aidl::a::ByteEnum _aidl_value;
+ if ((_aidl_ret_status = AParcel_readByte(_parcel, reinterpret_cast<int8_t*>(&_aidl_value))) != STATUS_OK) return _aidl_ret_status;
+ set<e>(std::move(_aidl_value));
+ return STATUS_OK; }
+ }
+ return STATUS_BAD_VALUE;
+}
+binder_status_t Foo::writeToParcel(AParcel* _parcel) const {
+ binder_status_t _aidl_ret_status = AParcel_writeInt32(_parcel, getTag());
+ if (_aidl_ret_status != STATUS_OK) return _aidl_ret_status;
+ switch (getTag()) {
+ case ns: return ::ndk::AParcel_writeVector(_parcel, get<ns>());
+ case e: return AParcel_writeByte(_parcel, static_cast<int8_t>(get<e>()));
+ }
+ abort();
+}
+
+} // namespace a
+} // namespace aidl
+)";
+
const char kUnionExampleExpectedOutputJava[] = R"(/*
* This file is auto-generated. DO NOT MODIFY.
*/
@@ -3007,11 +3133,17 @@
{"out/a/Foo.h", kUnionExampleExpectedOutputCppHeader}}));
}
+TEST_F(AidlUnionTest, Example_Ndk) {
+ Compile("ndk");
+ EXPECT_COMPILE_OUTPUTS(
+ map<string, string>({{"out/a/Foo.cpp", kUnionExampleExpectedOutputNdkSource},
+ {"out/aidl/a/Foo.h", kUnionExampleExpectedOutputNdkHeader}}));
+}
+
TEST_F(AidlUnionTest, Example_Java) {
Compile("java");
EXPECT_COMPILE_OUTPUTS(
map<string, string>({{"out/a/Foo.java", kUnionExampleExpectedOutputJava}}));
- // TODO(b/170784707) NDK
// TODO(b/170689477) Rust
}