/* * 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. */ #include #include #include #include #include #include #include #include #include using aidl::android::aidl::fixedsizearray::FixedSizeArrayExample; using BnRepeatFixedSizeArray = aidl::android::aidl::fixedsizearray::FixedSizeArrayExample::BnRepeatFixedSizeArray; using BpRepeatFixedSizeArray = aidl::android::aidl::fixedsizearray::FixedSizeArrayExample::BpRepeatFixedSizeArray; using IntParcelable = aidl::android::aidl::fixedsizearray::FixedSizeArrayExample::IntParcelable; using IRepeatFixedSizeArray = aidl::android::aidl::fixedsizearray::FixedSizeArrayExample::IRepeatFixedSizeArray; using BnEmptyInterface = aidl::android::aidl::fixedsizearray::FixedSizeArrayExample::BnEmptyInterface; using aidl::android::aidl::tests::BackendType; using aidl::android::aidl::tests::ITestService; using aidl::android::aidl::tests::RecursiveList; using aidl::android::aidl::tests::Union; using android::OK; using ndk::AParcel_readData; using ndk::AParcel_writeData; using ndk::ScopedAStatus; using ndk::SharedRefBase; using ndk::SpAIBinder; struct AidlTest : testing::Test { template std::shared_ptr getService() { ndk::SpAIBinder binder = ndk::SpAIBinder(AServiceManager_getService(T::descriptor)); return T::fromBinder(binder); } }; // TODO(b/196454897): copy more tests from aidl_test_client 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 = getService()->ReverseList(*head, &reversed); ASSERT_TRUE(status.isOk()); // 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 = getService()->GetUnionTags(unions, &tags); ASSERT_TRUE(status.isOk()); EXPECT_EQ(tags, (std::vector{})); // test non-empty unions.push_back(Union::make()); unions.push_back(Union::make()); status = getService()->GetUnionTags(unions, &tags); ASSERT_TRUE(status.isOk()); EXPECT_EQ(tags, (std::vector{Union::n, Union::ns})); } TEST_F(AidlTest, FixedSizeArray) { auto parcel = AParcel_create(); 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)); AParcel_setDataPosition(parcel, 0); FixedSizeArrayExample q; EXPECT_EQ(OK, q.readFromParcel(parcel)); EXPECT_EQ(p, q); AParcel_delete(parcel); } TEST_F(AidlTest, FixedSizeArrayWithValuesAtNullableFields) { auto parcel = AParcel_create(); 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)); AParcel_setDataPosition(parcel, 0); FixedSizeArrayExample q; EXPECT_EQ(OK, q.readFromParcel(parcel)); EXPECT_EQ(p, q); AParcel_delete(parcel); } TEST_F(AidlTest, FixedSizeArrayOfBytesShouldBePacked) { auto parcel = AParcel_create(); std::array, 2> byte_array; byte_array[0] = {1, 2, 3}; byte_array[1] = {4, 5, 6}; EXPECT_EQ(OK, AParcel_writeData(parcel, byte_array)); AParcel_setDataPosition(parcel, 0); int32_t len; EXPECT_EQ(OK, AParcel_readData(parcel, &len)); EXPECT_EQ(2, len); std::vector byte_vector; EXPECT_EQ(OK, AParcel_readData(parcel, &byte_vector)); EXPECT_EQ(byte_vector, (std::vector{1, 2, 3})); EXPECT_EQ(OK, AParcel_readData(parcel, &byte_vector)); EXPECT_EQ(byte_vector, (std::vector{4, 5, 6})); AParcel_delete(parcel); } 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) { auto service = getService(); CheckRepeat(service, &IRepeatFixedSizeArray::RepeatBytes, (std::array{1, 2, 3})); CheckRepeat(service, &IRepeatFixedSizeArray::RepeatInts, (std::array{1, 2, 3})); auto binder1 = SharedRefBase::make()->asBinder(); auto binder2 = SharedRefBase::make()->asBinder(); auto binder3 = SharedRefBase::make()->asBinder(); CheckRepeat(service, &IRepeatFixedSizeArray::RepeatBinders, (std::array{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})); }