/* * Copyright (C) 2015 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 #include #include #include #include #include #include #include "aidl_test_client.h" #include #include using android::IInterface; using android::sp; using android::String16; using android::String8; using android::aidl::fixedsizearray::FixedSizeArrayExample; using android::aidl::tests::BadParcelable; using android::aidl::tests::ConstantExpressionEnum; using android::aidl::tests::GenericStructuredParcelable; using android::aidl::tests::INamedCallback; using android::aidl::tests::IntEnum; using android::aidl::tests::ITestService; using android::aidl::tests::OtherParcelableForToString; using android::aidl::tests::ParcelableForToString; using android::aidl::tests::RecursiveList; using android::aidl::tests::SimpleParcelable; using android::aidl::tests::StructuredParcelable; using android::aidl::tests::Union; using android::aidl::tests::extension::ExtendableParcelable; using android::aidl::tests::extension::MyExt; using android::aidl::tests::extension::MyExt2; using android::aidl::tests::extension::MyExtLike; using android::aidl::tests::unions::EnumUnion; using IntParcelable = android::aidl::fixedsizearray::FixedSizeArrayExample::IntParcelable; using IRepeatFixedSizeArray = android::aidl::fixedsizearray::FixedSizeArrayExample::IRepeatFixedSizeArray; using android::BBinder; using android::IBinder; using android::OK; using android::binder::Status; using android::os::PersistableBundle; using std::string; using std::vector; TEST_F(AidlTest, BadParcelable) { if (!cpp_java_tests) GTEST_SKIP() << "Service does not support the CPP/Java-only tests."; BadParcelable output; { BadParcelable bad(/*bad=*/true, "Booya", 42); Status status = cpp_java_tests->RepeatBadParcelable(bad, &output); ASSERT_FALSE(status.isOk()); EXPECT_EQ(status.exceptionCode(), Status::Exception::EX_BAD_PARCELABLE); } { BadParcelable not_bad(/*bad=*/false, "Booya", 42); Status status = cpp_java_tests->RepeatBadParcelable(not_bad, &output); ASSERT_TRUE(status.isOk()); EXPECT_EQ(not_bad, output); } } TEST_F(AidlTest, RepeatSimpleParcelable) { if (!cpp_java_tests) GTEST_SKIP() << "Service does not support the CPP/Java-only tests."; SimpleParcelable input("Booya", 42); SimpleParcelable out_param, returned; Status status = cpp_java_tests->RepeatSimpleParcelable(input, &out_param, &returned); ASSERT_TRUE(status.isOk()) << status.toString8(); EXPECT_EQ(input, out_param) << input.toString() << " " << out_param.toString(); EXPECT_EQ(input, returned) << input.toString() << " " << returned.toString(); } TEST_F(AidlTest, RepeatGenericStructureParcelable) { if (!cpp_java_tests) GTEST_SKIP() << "Service does not support the CPP/Java-only tests."; GenericStructuredParcelable input, out_param, returned; input.a = 41; input.b = 42; Status status = cpp_java_tests->RepeatGenericParcelable(input, &out_param, &returned); ASSERT_TRUE(status.isOk()) << status.toString8(); EXPECT_EQ(input, out_param); EXPECT_EQ(input, returned); } TEST_F(AidlTest, ReverseSimpleParcelable) { if (!cpp_java_tests) GTEST_SKIP() << "Service does not support the CPP/Java-only tests."; const vector original{SimpleParcelable("first", 0), SimpleParcelable("second", 1), SimpleParcelable("third", 2)}; vector repeated; if (backend == BackendType::JAVA) { repeated = vector(original.size()); } vector reversed; Status status = cpp_java_tests->ReverseSimpleParcelables(original, &repeated, &reversed); ASSERT_TRUE(status.isOk()) << status.toString8(); EXPECT_EQ(repeated, original); std::reverse(reversed.begin(), reversed.end()); EXPECT_EQ(reversed, original); } TEST_F(AidlTest, ConfirmPersistableBundles) { if (!cpp_java_tests) GTEST_SKIP() << "Service does not support the CPP/Java-only tests."; PersistableBundle empty_bundle, returned; Status status = cpp_java_tests->RepeatPersistableBundle(empty_bundle, &returned); ASSERT_TRUE(status.isOk()) << status.toString8(); EXPECT_EQ(empty_bundle, returned); } TEST_F(AidlTest, ConfirmPersistableBundlesNonEmpty) { if (!cpp_java_tests) GTEST_SKIP() << "Service does not support the CPP/Java-only tests."; PersistableBundle non_empty_bundle, returned; non_empty_bundle.putBoolean(String16("test_bool"), false); non_empty_bundle.putInt(String16("test_int"), 33); non_empty_bundle.putLong(String16("test_long"), 34359738368L); non_empty_bundle.putDouble(String16("test_double"), 1.1); non_empty_bundle.putString(String16("test_string"), String16("Woot!")); non_empty_bundle.putBooleanVector(String16("test_bool_vector"), {true, false, true}); non_empty_bundle.putIntVector(String16("test_int_vector"), {33, 44, 55, 142}); non_empty_bundle.putLongVector(String16("test_long_vector"), {34L, 8371L, 34359738375L}); non_empty_bundle.putDoubleVector(String16("test_double_vector"), {2.2, 5.4}); non_empty_bundle.putStringVector(String16("test_string_vector"), {String16("hello"), String16("world!")}); PersistableBundle nested_bundle; nested_bundle.putInt(String16("test_nested_int"), 345); non_empty_bundle.putPersistableBundle(String16("test_persistable_bundle"), nested_bundle); Status status = cpp_java_tests->RepeatPersistableBundle(non_empty_bundle, &returned); ASSERT_TRUE(status.isOk()) << status.toString8(); EXPECT_EQ(non_empty_bundle, returned); } TEST_F(AidlTest, ReversePersistableBundles) { if (!cpp_java_tests) GTEST_SKIP() << "Service does not support the CPP/Java-only tests."; PersistableBundle first; PersistableBundle second; PersistableBundle third; first.putInt(String16("test_int"), 1231); second.putLong(String16("test_long"), 222222L); third.putDouble(String16("test_double"), 10.8); const vector original{first, second, third}; vector repeated; if (backend == BackendType::JAVA) { repeated = vector(original.size()); } vector reversed; Status status = cpp_java_tests->ReversePersistableBundles(original, &repeated, &reversed); ASSERT_TRUE(status.isOk()) << status.toString8(); EXPECT_EQ(repeated, original); std::reverse(reversed.begin(), reversed.end()); EXPECT_EQ(reversed, original); } TEST_F(AidlTest, ReverseUnion) { if (!cpp_java_tests) GTEST_SKIP() << "Service does not support the CPP/Java-only tests."; Union original = Union::make({1, 2, 3}); Union repeated, reversed; Status status = cpp_java_tests->ReverseUnion(original, &repeated, &reversed); ASSERT_TRUE(status.isOk()) << status.toString8(); EXPECT_EQ(repeated, original); std::reverse(reversed.get().begin(), reversed.get().end()); EXPECT_EQ(reversed, original); } TEST_F(AidlTest, UnionUsage) { // default ctor inits with first member's default value EXPECT_EQ(Union::make(), Union()); // make(...) to create a value for a tag. Union one_two_three = Union::make({1, 2, 3}); // getTag() queries the tag of the content EXPECT_EQ(Union::ns, one_two_three.getTag()); // Ctor(...) works if a target tag has a unique type among fields. EXPECT_EQ(one_two_three, Union(std::vector{1, 2, 3})); EXPECT_EQ(one_two_three, std::vector({1, 2, 3})); // Use std::in_place_index to avoid "move" // Note that make(...) involves "move" of the content value EXPECT_EQ(Union::make(3, 0), Union(std::in_place_index(Union::ns)>, 3, 0)); Union one_two = one_two_three; // get can be used to modify the content one_two.get().pop_back(); EXPECT_EQ(one_two, std::vector({1, 2})); // get can be lvalue one_two.get() = std::vector{1, 2}; EXPECT_EQ(one_two, std::vector({1, 2})); // abort with a bad access EXPECT_DEATH(one_two.get(), "bad access"); // set(...) overwrites the content with a new tag one_two_three.set("123"); EXPECT_EQ(one_two_three, std::string("123")); // Or, you can simply assign a new value. // note that this works only if the target type is unique one_two_three = std::vector{"1", "2", "3"}; EXPECT_EQ(Union::ss, one_two_three.getTag()); } TEST_F(AidlTest, UnionDefaultConstructorInitializeWithFirstMember) { EXPECT_EQ(Union::make(), Union()); // int[] ns EXPECT_EQ(EnumUnion::make(IntEnum::FOO), EnumUnion()); // IntEnum intEnum = IntEnum.FOO } TEST_F(AidlTest, StructuredParcelableEquality) { // TODO: break up equality tests, these are hard to read, because you need to // keep the state of the parcelables in mind StructuredParcelable parcelable1; StructuredParcelable parcelable2; parcelable1.f = 11; parcelable2.f = 11; service->FillOutStructuredParcelable(&parcelable1); service->FillOutStructuredParcelable(&parcelable2); sp callback1; sp callback2; service->GetOtherTestService(String16("callback1"), &callback1); service->GetOtherTestService(String16("callback2"), &callback2); parcelable1.ibinder = IInterface::asBinder(callback1); parcelable2.ibinder = IInterface::asBinder(callback1); EXPECT_EQ(parcelable1, parcelable2); parcelable1.f = 0; EXPECT_LT(parcelable1, parcelable2); parcelable1.f = 11; parcelable1.shouldBeJerry = "Jarry"; EXPECT_LT(parcelable1, parcelable2); parcelable1.shouldBeJerry = "Jerry"; parcelable2.shouldContainThreeFs = {}; EXPECT_GT(parcelable1, parcelable2); parcelable2.shouldContainThreeFs = {parcelable2.f, parcelable2.f, parcelable2.f}; parcelable2.shouldBeIntBar = IntEnum::FOO; EXPECT_GT(parcelable1, parcelable2); parcelable2.shouldBeIntBar = IntEnum::BAR; parcelable2.ibinder = IInterface::asBinder(callback2); EXPECT_NE(parcelable1, parcelable2); } TEST_F(AidlTest, ConfirmStructuredParcelables) { constexpr int kDesiredValue = 23; StructuredParcelable parcelable; parcelable.f = kDesiredValue; EXPECT_EQ(parcelable.stringDefaultsToFoo, String16("foo")); EXPECT_EQ(parcelable.byteDefaultsToFour, 4); EXPECT_EQ(parcelable.intDefaultsToFive, 5); EXPECT_EQ(parcelable.longDefaultsToNegativeSeven, -7); EXPECT_EQ(parcelable.booleanDefaultsToTrue, true); EXPECT_EQ(parcelable.charDefaultsToC, 'C'); EXPECT_TRUE(parcelable.floatDefaultsToPi == 3.14f) << parcelable.floatDefaultsToPi; EXPECT_TRUE(parcelable.doubleWithDefault == -3.14e17) << parcelable.doubleWithDefault; EXPECT_EQ(parcelable.boolDefault, false); EXPECT_EQ(parcelable.byteDefault, 0); EXPECT_EQ(parcelable.intDefault, 0); EXPECT_EQ(parcelable.longDefault, 0); EXPECT_EQ(parcelable.floatDefault, 0.0f); EXPECT_EQ(parcelable.doubleDefault, 0.0); ASSERT_EQ(parcelable.arrayDefaultsTo123.size(), 3u); EXPECT_EQ(parcelable.arrayDefaultsTo123[0], 1); EXPECT_EQ(parcelable.arrayDefaultsTo123[1], 2); EXPECT_EQ(parcelable.arrayDefaultsTo123[2], 3); EXPECT_TRUE(parcelable.arrayDefaultsToEmpty.empty()); EXPECT_EQ(parcelable.defaultWithFoo, IntEnum::FOO); service->FillOutStructuredParcelable(&parcelable); ASSERT_EQ(parcelable.shouldContainThreeFs.size(), 3u); EXPECT_EQ(parcelable.shouldContainThreeFs[0], kDesiredValue); EXPECT_EQ(parcelable.shouldContainThreeFs[1], kDesiredValue); EXPECT_EQ(parcelable.shouldContainThreeFs[2], kDesiredValue); EXPECT_EQ(parcelable.shouldBeJerry, "Jerry"); EXPECT_EQ(parcelable.int32_min, INT32_MIN); EXPECT_EQ(parcelable.int32_max, INT32_MAX); EXPECT_EQ(parcelable.int64_max, INT64_MAX); EXPECT_EQ(parcelable.hexInt32_neg_1, -1); for (size_t ndx = 0; ndx < parcelable.int8_1.size(); ndx++) { EXPECT_EQ(parcelable.int8_1[ndx], 1) << ndx; } for (size_t ndx = 0; ndx < parcelable.int32_1.size(); ndx++) { EXPECT_EQ(parcelable.int32_1[ndx], 1) << ndx; } for (size_t ndx = 0; ndx < parcelable.int64_1.size(); ndx++) { EXPECT_EQ(parcelable.int64_1[ndx], 1) << ndx; } EXPECT_EQ(parcelable.hexInt32_pos_1, 1); EXPECT_EQ(parcelable.hexInt64_pos_1, 1); EXPECT_EQ(static_cast(parcelable.const_exprs_1), 1); EXPECT_EQ(static_cast(parcelable.const_exprs_2), 1); EXPECT_EQ(static_cast(parcelable.const_exprs_3), 1); EXPECT_EQ(static_cast(parcelable.const_exprs_4), 1); EXPECT_EQ(static_cast(parcelable.const_exprs_5), 1); EXPECT_EQ(static_cast(parcelable.const_exprs_6), 1); EXPECT_EQ(static_cast(parcelable.const_exprs_7), 1); EXPECT_EQ(static_cast(parcelable.const_exprs_8), 1); EXPECT_EQ(static_cast(parcelable.const_exprs_9), 1); EXPECT_EQ(static_cast(parcelable.const_exprs_10), 1); EXPECT_EQ(parcelable.addString1, "hello world!"); EXPECT_EQ(parcelable.addString2, "The quick brown fox jumps over the lazy dog."); EXPECT_EQ(StructuredParcelable::BIT0 | StructuredParcelable::BIT2, parcelable.shouldSetBit0AndBit2); EXPECT_EQ(parcelable.u->get(), vector({1, 2, 3})); EXPECT_EQ(parcelable.shouldBeConstS1->get(), Union::S1()); } TEST_F(AidlTest, EmptyParcelableHolder) { using namespace android::aidl::tests::extension; android::Parcel parcel; { ExtendableParcelable ep; ep.writeToParcel(&parcel); std::shared_ptr emptyExt; ep.ext.getParcelable(&emptyExt); EXPECT_FALSE(emptyExt); } { parcel.setDataPosition(0); ExtendableParcelable ep; ep.readFromParcel(&parcel); std::shared_ptr emptyExt; ep.ext.getParcelable(&emptyExt); EXPECT_FALSE(emptyExt); } } TEST_F(AidlTest, ParcelableHolderEqualityOperator) { auto ph1 = android::os::ParcelableHolder(android::Parcelable::Stability::STABILITY_LOCAL); auto ph2 = android::os::ParcelableHolder(android::Parcelable::Stability::STABILITY_LOCAL); auto ph3 = android::os::ParcelableHolder(android::Parcelable::Stability::STABILITY_LOCAL); auto ptr1 = std::make_shared(); auto ptr2 = std::make_shared(); ptr1->a = 1; ptr1->b = "a"; ptr2->a = 1; ptr2->b = "a"; ph1.setParcelable(ptr1); ph2.setParcelable(ptr1); ph3.setParcelable(ptr2); // ParcelableHolder always uses its address as a comparison criterion. EXPECT_TRUE(ph1 != ph2); EXPECT_TRUE(ph2 != ph3); EXPECT_TRUE(ph1 == ph1); EXPECT_TRUE(ph2 == ph2); EXPECT_TRUE(ph3 == ph3); android::Parcel parcel; ph1.writeToParcel(&parcel); ph2.writeToParcel(&parcel); ph3.writeToParcel(&parcel); parcel.setDataPosition(0); ph1.readFromParcel(&parcel); ph2.readFromParcel(&parcel); ph3.readFromParcel(&parcel); // ParcelableHolder always uses its address as a comparison criterion. EXPECT_TRUE(ph1 != ph2); EXPECT_TRUE(ph2 != ph3); EXPECT_TRUE(ph1 == ph1); EXPECT_TRUE(ph2 == ph2); EXPECT_TRUE(ph3 == ph3); } TEST_F(AidlTest, NativeExtednableParcelable) { using namespace android::aidl::tests::extension; MyExt ext; ext.a = 42; ext.b = "EXT"; MyExt2 ext2; ext2.a = 42; ext2.b.a = 24; ext2.b.b = "INEXT"; ext2.c = "EXT2"; android::Parcel parcel; { ExtendableParcelable ep; ep.a = 1; ep.b = "a"; ep.c = 42L; EXPECT_TRUE(ep.ext.setParcelable(ext) == android::OK); EXPECT_TRUE(ep.ext2.setParcelable(ext2) == android::OK); std::shared_ptr extLike; ep.ext.getParcelable(&extLike); EXPECT_FALSE(extLike) << "The extension type must be MyExt, so it has to fail even though " "MyExtLike has the same structure as MyExt."; std::shared_ptr actualExt; ep.ext.getParcelable(&actualExt); std::shared_ptr actualExt2; ep.ext2.getParcelable(&actualExt2); EXPECT_TRUE(actualExt); EXPECT_TRUE(actualExt2); EXPECT_EQ(ext, *actualExt); EXPECT_EQ(ext2, *actualExt2); ep.writeToParcel(&parcel); } parcel.setDataPosition(0); { ExtendableParcelable ep; ep.readFromParcel(&parcel); std::shared_ptr extLike; ep.ext.getParcelable(&extLike); EXPECT_FALSE(extLike) << "The extension type must be MyExt, so it has to fail even though " "MyExtLike has the same structure as MyExt."; std::shared_ptr actualExt; ep.ext.getParcelable(&actualExt); std::shared_ptr actualExt2; ep.ext2.getParcelable(&actualExt2); std::shared_ptr emptyExt; ep.ext2.getParcelable(&emptyExt); EXPECT_FALSE(emptyExt); EXPECT_TRUE(actualExt); EXPECT_TRUE(actualExt2); EXPECT_EQ(ext, *actualExt); EXPECT_EQ(ext2, *actualExt2); } } TEST_F(AidlTest, ParcelableToString) { ParcelableForToString p; p.intValue = 10; p.intArray = {20, 30}; p.longValue = 100L; p.longArray = {200L, 300L}; p.doubleValue = 3.14; p.doubleArray = {1.1, 1.2}; p.floatValue = 3.14f; p.floatArray = {1.1f, 1.2f}; p.byteValue = 3; p.byteArray = {5, 6}; p.booleanValue = true; p.booleanArray = {true, false}; p.stringValue = String16("this is a string"); p.stringArray = {String16("hello"), String16("world")}; p.stringList = {String16("alice"), String16("bob")}; OtherParcelableForToString op; op.field = String16("other"); p.parcelableValue = op; p.parcelableArray = {op, op}; p.enumValue = IntEnum::FOO; p.enumArray = {IntEnum::FOO, IntEnum::BAR}; // p.nullArray = null; // p.nullList = null; GenericStructuredParcelable gen; gen.a = 1; gen.b = 2; p.parcelableGeneric = gen; p.unionValue = Union(std::vector{"union", "value"}); const string expected = "ParcelableForToString{" "intValue: 10, " "intArray: [20, 30], " "longValue: 100, " "longArray: [200, 300], " "doubleValue: 3.140000, " "doubleArray: [1.100000, 1.200000], " "floatValue: 3.140000, " "floatArray: [1.100000, 1.200000], " "byteValue: 3, " "byteArray: [5, 6], " "booleanValue: true, " "booleanArray: [true, false], " "stringValue: this is a string, " "stringArray: [hello, world], " "stringList: [alice, bob], " "parcelableValue: OtherParcelableForToString{field: other}, " "parcelableArray: [" "OtherParcelableForToString{field: other}, " "OtherParcelableForToString{field: other}], " "enumValue: FOO, " "enumArray: [FOO, BAR], " "nullArray: [], " "nullList: [], " "parcelableGeneric: GenericStructuredParcelable{a: 1, b: 2}, " "unionValue: Union{ss: [union, value]}" "}"; EXPECT_EQ(expected, p.toString()); } TEST_F(AidlTest, ReverseRecursiveList) { std::unique_ptr head; for (int i = 0; i < 10; i++) { auto node = std::make_unique(); node->value = i; node->next = std::move(head); head = std::move(node); } // head: [9, 8, ... 0] RecursiveList reversed; auto status = service->ReverseList(*head, &reversed); ASSERT_TRUE(status.isOk()) << status.toString8(); // reversed should be [0, 1, .. 9] RecursiveList* cur = &reversed; for (int i = 0; i < 10; i++) { EXPECT_EQ(i, cur->value); cur = cur->next.get(); } EXPECT_EQ(nullptr, cur); } TEST_F(AidlTest, GetUnionTags) { std::vector unions; std::vector tags; // test empty auto status = service->GetUnionTags(unions, &tags); ASSERT_TRUE(status.isOk()) << status.toString8(); EXPECT_EQ(tags, (std::vector{})); // test non-empty unions.push_back(Union::make()); unions.push_back(Union::make()); status = service->GetUnionTags(unions, &tags); ASSERT_TRUE(status.isOk()) << status.toString8(); EXPECT_EQ(tags, (std::vector{Union::n, Union::ns})); } TEST_F(AidlTest, FixedSizeArray) { android::Parcel parcel; FixedSizeArrayExample p; p.byteMatrix[0][0] = 0; p.byteMatrix[0][1] = 1; p.byteMatrix[1][0] = 2; p.byteMatrix[1][1] = 3; p.floatMatrix[0][0] = 0.f; p.floatMatrix[0][1] = 1.f; p.floatMatrix[1][0] = 2.f; p.floatMatrix[1][1] = 3.f; EXPECT_EQ(OK, p.writeToParcel(&parcel)); parcel.setDataPosition(0); FixedSizeArrayExample q; EXPECT_EQ(OK, q.readFromParcel(&parcel)); EXPECT_EQ(p, q); } TEST_F(AidlTest, FixedSizeArrayWithValuesAtNullableFields) { android::Parcel parcel; FixedSizeArrayExample p; p.boolNullableArray = std::array{true, false}; p.byteNullableArray = std::array{42, 0}; p.stringNullableArray = std::array, 2>{"hello", "world"}; p.boolNullableMatrix.emplace(); p.boolNullableMatrix->at(0) = std::array{true, false}; p.byteNullableMatrix.emplace(); p.byteNullableMatrix->at(0) = std::array{42, 0}; p.stringNullableMatrix.emplace(); p.stringNullableMatrix->at(0) = std::array, 2>{"hello", "world"}; EXPECT_EQ(OK, p.writeToParcel(&parcel)); parcel.setDataPosition(0); FixedSizeArrayExample q; EXPECT_EQ(OK, q.readFromParcel(&parcel)); EXPECT_EQ(p, q); } TEST_F(AidlTest, FixedSizeArrayOfBytesShouldBePacked) { android::Parcel parcel; std::array, 2> byte_array; byte_array[0] = {1, 2, 3}; byte_array[1] = {4, 5, 6}; EXPECT_EQ(OK, parcel.writeFixedArray(byte_array)); parcel.setDataPosition(0); int32_t len; EXPECT_EQ(OK, parcel.readInt32(&len)); EXPECT_EQ(2, len); std::vector byte_vector; EXPECT_EQ(OK, parcel.readByteVector(&byte_vector)); EXPECT_EQ(byte_vector, (std::vector{1, 2, 3})); EXPECT_EQ(OK, parcel.readByteVector(&byte_vector)); EXPECT_EQ(byte_vector, (std::vector{4, 5, 6})); } template void CheckRepeat(Service service, MemFn fn, Input input) { Input out1, out2; EXPECT_TRUE(std::invoke(fn, service, input, &out1, &out2).isOk()); EXPECT_EQ(input, out1); EXPECT_EQ(input, out2); } template std::array, 2> Make2dArray(std::initializer_list values) { std::array, 2> arr = {}; auto it = std::begin(values); for (auto& row : arr) { for (auto& el : row) { if (it == std::end(values)) break; el = *it++; } } return arr; } TEST_F(AidlTest, FixedSizeArrayOverBinder) { sp service; ASSERT_EQ(OK, getService(IRepeatFixedSizeArray::descriptor, &service)); CheckRepeat(service, &IRepeatFixedSizeArray::RepeatBytes, (std::array{1, 2, 3})); CheckRepeat(service, &IRepeatFixedSizeArray::RepeatInts, (std::array{1, 2, 3})); sp binder1 = new BBinder(); sp binder2 = new BBinder(); sp binder3 = new BBinder(); CheckRepeat(service, &IRepeatFixedSizeArray::RepeatBinders, (std::array, 3>{binder1, binder2, binder3})); IntParcelable p1, p2, p3; p1.value = 1; p2.value = 2; p3.value = 3; CheckRepeat(service, &IRepeatFixedSizeArray::RepeatParcelables, (std::array{p1, p2, p3})); CheckRepeat(service, &IRepeatFixedSizeArray::Repeat2dBytes, Make2dArray({1, 2, 3})); CheckRepeat(service, &IRepeatFixedSizeArray::Repeat2dInts, Make2dArray({1, 2, 3})); // Not-nullable CheckRepeat(service, &IRepeatFixedSizeArray::Repeat2dBinders, Make2dArray>({binder1, binder2, binder3, binder1, binder2, binder3})); CheckRepeat(service, &IRepeatFixedSizeArray::Repeat2dParcelables, Make2dArray({p1, p2, p3})); }