Add test for trunk stable workaround
This test is an example of using the same source code for different
versions of the AIDL library.
Test: atest aidl_ndk_v1_trunk_stable_unittest
Test: atest aidl_ndk_v2_trunk_stable_unittest
Bug: none
Change-Id: I6d0872931287e4127c9fef213250d67cfee3bb4e
diff --git a/tests/trunk_stable_test/Android.bp b/tests/trunk_stable_test/Android.bp
new file mode 100644
index 0000000..64336e7
--- /dev/null
+++ b/tests/trunk_stable_test/Android.bp
@@ -0,0 +1,80 @@
+// 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.
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "system_tools_aidl_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["system_tools_aidl_license"],
+}
+
+aidl_interface {
+ name: "android.aidl.test.trunk",
+ srcs: ["android/aidl/test/trunk/*.aidl"],
+ flags: ["-Werror"],
+ backend: {
+ rust: {
+ enabled: true,
+ },
+ },
+ versions_with_info: [
+ {
+ version: "1",
+ imports: [],
+ },
+ ],
+ frozen: false,
+
+}
+
+// Test using the same client and server source code including different
+// versions of the generated AIDL library.
+// This is an example of a possible solution to dealing with different
+// configurations of the build without needing to modify the source code.
+// This is the version of the test that uses the V1 library with the
+// V2 code behind #ifdefs.
+cc_test {
+ name: "aidl_ndk_V1_trunk_stable_unittest",
+ srcs: ["trunk_ndk_unittest.cpp"],
+ shared_libs: [
+ "libbinder_ndk",
+ "libbase",
+ ],
+ cflags: [
+ "-DAIDL_TEST_TRUNK_VER=1",
+ ],
+ static_libs: [
+ "android.aidl.test.trunk-V1-ndk",
+ ],
+ require_root: true,
+}
+
+// This is the version of the test that uses the latest V2 library.
+cc_test {
+ name: "aidl_ndk_V2_trunk_stable_unittest",
+ srcs: ["trunk_ndk_unittest.cpp"],
+ shared_libs: [
+ "libbinder_ndk",
+ "libbase",
+ ],
+ cflags: [
+ "-DAIDL_TEST_TRUNK_VER=2",
+ ],
+ static_libs: [
+ "android.aidl.test.trunk-V2-ndk",
+ ],
+ require_root: true,
+}
diff --git a/tests/trunk_stable_test/aidl_api/android.aidl.test.trunk/1/.hash b/tests/trunk_stable_test/aidl_api/android.aidl.test.trunk/1/.hash
new file mode 100644
index 0000000..890f5f5
--- /dev/null
+++ b/tests/trunk_stable_test/aidl_api/android.aidl.test.trunk/1/.hash
@@ -0,0 +1 @@
+88311b9118fb6fe9eff4a2ca19121de0587f6d5f
diff --git a/tests/trunk_stable_test/aidl_api/android.aidl.test.trunk/1/android/aidl/test/trunk/ITrunkStableTest.aidl b/tests/trunk_stable_test/aidl_api/android.aidl.test.trunk/1/android/aidl/test/trunk/ITrunkStableTest.aidl
new file mode 100644
index 0000000..98bbd2f
--- /dev/null
+++ b/tests/trunk_stable_test/aidl_api/android.aidl.test.trunk/1/android/aidl/test/trunk/ITrunkStableTest.aidl
@@ -0,0 +1,43 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.aidl.test.trunk;
+interface ITrunkStableTest {
+ android.aidl.test.trunk.ITrunkStableTest.MyParcelable repeatParcelable(in android.aidl.test.trunk.ITrunkStableTest.MyParcelable input);
+ android.aidl.test.trunk.ITrunkStableTest.MyEnum repeatEnum(in android.aidl.test.trunk.ITrunkStableTest.MyEnum input);
+ android.aidl.test.trunk.ITrunkStableTest.MyUnion repeatUnion(in android.aidl.test.trunk.ITrunkStableTest.MyUnion input);
+ void callMyCallback(in android.aidl.test.trunk.ITrunkStableTest.IMyCallback cb);
+ parcelable MyParcelable {
+ int a;
+ int b;
+ }
+ enum MyEnum {
+ ZERO,
+ ONE,
+ TWO,
+ }
+ union MyUnion {
+ int a;
+ int b;
+ }
+ interface IMyCallback {
+ android.aidl.test.trunk.ITrunkStableTest.MyParcelable repeatParcelable(in android.aidl.test.trunk.ITrunkStableTest.MyParcelable input);
+ android.aidl.test.trunk.ITrunkStableTest.MyEnum repeatEnum(in android.aidl.test.trunk.ITrunkStableTest.MyEnum input);
+ android.aidl.test.trunk.ITrunkStableTest.MyUnion repeatUnion(in android.aidl.test.trunk.ITrunkStableTest.MyUnion input);
+ }
+}
diff --git a/tests/trunk_stable_test/aidl_api/android.aidl.test.trunk/current/android/aidl/test/trunk/ITrunkStableTest.aidl b/tests/trunk_stable_test/aidl_api/android.aidl.test.trunk/current/android/aidl/test/trunk/ITrunkStableTest.aidl
new file mode 100644
index 0000000..2aa3bb1
--- /dev/null
+++ b/tests/trunk_stable_test/aidl_api/android.aidl.test.trunk/current/android/aidl/test/trunk/ITrunkStableTest.aidl
@@ -0,0 +1,52 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.aidl.test.trunk;
+interface ITrunkStableTest {
+ android.aidl.test.trunk.ITrunkStableTest.MyParcelable repeatParcelable(in android.aidl.test.trunk.ITrunkStableTest.MyParcelable input);
+ android.aidl.test.trunk.ITrunkStableTest.MyEnum repeatEnum(in android.aidl.test.trunk.ITrunkStableTest.MyEnum input);
+ android.aidl.test.trunk.ITrunkStableTest.MyUnion repeatUnion(in android.aidl.test.trunk.ITrunkStableTest.MyUnion input);
+ void callMyCallback(in android.aidl.test.trunk.ITrunkStableTest.IMyCallback cb);
+ android.aidl.test.trunk.ITrunkStableTest.MyOtherParcelable repeatOtherParcelable(in android.aidl.test.trunk.ITrunkStableTest.MyOtherParcelable input);
+ parcelable MyParcelable {
+ int a;
+ int b;
+ int c;
+ }
+ enum MyEnum {
+ ZERO,
+ ONE,
+ TWO,
+ THREE,
+ }
+ union MyUnion {
+ int a;
+ int b;
+ int c;
+ }
+ interface IMyCallback {
+ android.aidl.test.trunk.ITrunkStableTest.MyParcelable repeatParcelable(in android.aidl.test.trunk.ITrunkStableTest.MyParcelable input);
+ android.aidl.test.trunk.ITrunkStableTest.MyEnum repeatEnum(in android.aidl.test.trunk.ITrunkStableTest.MyEnum input);
+ android.aidl.test.trunk.ITrunkStableTest.MyUnion repeatUnion(in android.aidl.test.trunk.ITrunkStableTest.MyUnion input);
+ android.aidl.test.trunk.ITrunkStableTest.MyOtherParcelable repeatOtherParcelable(in android.aidl.test.trunk.ITrunkStableTest.MyOtherParcelable input);
+ }
+ parcelable MyOtherParcelable {
+ int a;
+ int b;
+ }
+}
diff --git a/tests/trunk_stable_test/android/aidl/test/trunk/ITrunkStableTest.aidl b/tests/trunk_stable_test/android/aidl/test/trunk/ITrunkStableTest.aidl
new file mode 100644
index 0000000..7c4ce2b
--- /dev/null
+++ b/tests/trunk_stable_test/android/aidl/test/trunk/ITrunkStableTest.aidl
@@ -0,0 +1,41 @@
+package android.aidl.test.trunk;
+
+interface ITrunkStableTest {
+ parcelable MyParcelable {
+ int a;
+ int b;
+ // New in V2
+ int c;
+ }
+ enum MyEnum {
+ ZERO,
+ ONE,
+ TWO,
+ // New in V2
+ THREE,
+ }
+ union MyUnion {
+ int a;
+ int b;
+ // New in V3
+ int c;
+ }
+ interface IMyCallback {
+ MyParcelable repeatParcelable(in MyParcelable input);
+ MyEnum repeatEnum(in MyEnum input);
+ MyUnion repeatUnion(in MyUnion input);
+ MyOtherParcelable repeatOtherParcelable(in MyOtherParcelable input);
+ }
+
+ MyParcelable repeatParcelable(in MyParcelable input);
+ MyEnum repeatEnum(in MyEnum input);
+ MyUnion repeatUnion(in MyUnion input);
+ void callMyCallback(in IMyCallback cb);
+
+ // New in V2
+ parcelable MyOtherParcelable {
+ int a;
+ int b;
+ }
+ MyOtherParcelable repeatOtherParcelable(in MyOtherParcelable input);
+}
diff --git a/tests/trunk_stable_test/trunk_ndk_unittest.cpp b/tests/trunk_stable_test/trunk_ndk_unittest.cpp
new file mode 100644
index 0000000..2ac721d
--- /dev/null
+++ b/tests/trunk_stable_test/trunk_ndk_unittest.cpp
@@ -0,0 +1,185 @@
+/*
+ * 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 "gtest/gtest.h"
+
+/* Shared Client/Service includes */
+#include <aidl/android/aidl/test/trunk/BnTrunkStableTest.h>
+#include <aidl/android/aidl/test/trunk/ITrunkStableTest.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <sys/prctl.h>
+
+/* AIDL Client includes */
+
+/* AIDL Service includes */
+#include <android/binder_process.h>
+
+#ifndef AIDL_TEST_TRUNK_VER
+#define AIDL_TEST_TRUNK_VER 2
+#endif
+
+using ::aidl::android::aidl::test::trunk::ITrunkStableTest;
+using ndk::ScopedAStatus;
+
+/* AIDL Client definition */
+class MyCallback : public ITrunkStableTest::BnMyCallback {
+ public:
+ ScopedAStatus repeatParcelable(const ITrunkStableTest::MyParcelable& in_input,
+ ITrunkStableTest::MyParcelable* _aidl_return) override {
+ *_aidl_return = in_input;
+ repeatParcelableCalled = true;
+ return ScopedAStatus::ok();
+ }
+ ScopedAStatus repeatEnum(const ITrunkStableTest::MyEnum in_input,
+ ITrunkStableTest::MyEnum* _aidl_return) override {
+ *_aidl_return = in_input;
+ repeatEnumCalled = true;
+ return ScopedAStatus::ok();
+ }
+ ScopedAStatus repeatUnion(const ITrunkStableTest::MyUnion& in_input,
+ ITrunkStableTest::MyUnion* _aidl_return) override {
+ *_aidl_return = in_input;
+ repeatUnionCalled = true;
+ return ScopedAStatus::ok();
+ }
+
+#if AIDL_TEST_TRUNK_VER >= 2
+ ScopedAStatus repeatOtherParcelable(const ITrunkStableTest::MyOtherParcelable& in_input,
+ ITrunkStableTest::MyOtherParcelable* _aidl_return) override {
+ *_aidl_return = in_input;
+ repeatOtherParcelableCalled = true;
+ return ScopedAStatus::ok();
+ }
+
+ bool repeatOtherParcelableCalled = false;
+#endif
+
+ bool repeatParcelableCalled = false;
+ bool repeatEnumCalled = false;
+ bool repeatUnionCalled = false;
+};
+
+class ClientTest : public testing::Test {
+ public:
+ void SetUp() override {
+ mService = ITrunkStableTest::fromBinder(
+ ndk::SpAIBinder(AServiceManager_waitForService(ITrunkStableTest::descriptor)));
+ ASSERT_NE(nullptr, mService);
+ }
+
+ std::shared_ptr<ITrunkStableTest> mService;
+};
+
+TEST_F(ClientTest, SanityCheck) {
+ ITrunkStableTest::MyParcelable a, b;
+ a.a = 12;
+ a.b = 13;
+#if AIDL_TEST_TRUNK_VER >= 2
+ a.c = 14;
+#endif
+ auto status = mService->repeatParcelable(a, &b);
+ EXPECT_TRUE(status.isOk());
+ EXPECT_EQ(a, b);
+}
+
+TEST_F(ClientTest, Callback) {
+ auto cb = ndk::SharedRefBase::make<MyCallback>();
+ auto status = mService->callMyCallback(cb);
+ EXPECT_TRUE(status.isOk());
+ EXPECT_TRUE(cb->repeatParcelableCalled);
+ EXPECT_TRUE(cb->repeatEnumCalled);
+ EXPECT_TRUE(cb->repeatUnionCalled);
+#if AIDL_TEST_TRUNK_VER >= 2
+ EXPECT_TRUE(cb->repeatOtherParcelableCalled);
+#endif
+}
+
+#if AIDL_TEST_TRUNK_VER >= 2
+TEST_F(ClientTest, CallV2Method) {
+ ITrunkStableTest::MyOtherParcelable a, b;
+ a.a = 12;
+ a.b = 13;
+ auto status = mService->repeatOtherParcelable(a, &b);
+ EXPECT_TRUE(status.isOk());
+ EXPECT_EQ(a, b);
+}
+#endif
+
+/* AIDL service definition */
+using ::aidl::android::aidl::test::trunk::BnTrunkStableTest;
+class TrunkStableTest : public BnTrunkStableTest {
+ ScopedAStatus repeatParcelable(const MyParcelable& in_input,
+ MyParcelable* _aidl_return) override {
+ *_aidl_return = in_input;
+ return ScopedAStatus::ok();
+ }
+ ScopedAStatus repeatEnum(const MyEnum in_input, MyEnum* _aidl_return) override {
+ *_aidl_return = in_input;
+ return ScopedAStatus::ok();
+ }
+ ScopedAStatus repeatUnion(const MyUnion& in_input, MyUnion* _aidl_return) override {
+ *_aidl_return = in_input;
+ return ScopedAStatus::ok();
+ }
+ ScopedAStatus callMyCallback(const std::shared_ptr<IMyCallback>& in_cb) override {
+ MyParcelable a, b;
+ MyEnum c = MyEnum::ZERO, d = MyEnum::ZERO;
+ MyUnion e, f;
+ auto status = in_cb->repeatParcelable(a, &b);
+ if (!status.isOk()) {
+ return status;
+ }
+ status = in_cb->repeatEnum(c, &d);
+ if (!status.isOk()) {
+ return status;
+ }
+ status = in_cb->repeatUnion(e, &f);
+#if AIDL_TEST_TRUNK_VER >= 2
+ if (!status.isOk()) {
+ return status;
+ }
+ MyOtherParcelable g, h;
+ status = in_cb->repeatOtherParcelable(g, &h);
+#endif
+ return status;
+ }
+#if AIDL_TEST_TRUNK_VER >= 2
+ ScopedAStatus repeatOtherParcelable(const ITrunkStableTest::MyOtherParcelable& in_input,
+ ITrunkStableTest::MyOtherParcelable* _aidl_return) override {
+ *_aidl_return = in_input;
+ return ScopedAStatus::ok();
+ }
+#endif
+};
+
+int run_service() {
+ auto trunk = ndk::SharedRefBase::make<TrunkStableTest>();
+ binder_status_t status =
+ AServiceManager_addService(trunk->asBinder().get(), TrunkStableTest::descriptor);
+ CHECK_EQ(status, STATUS_OK);
+
+ ABinderProcess_joinThreadPool();
+ return EXIT_FAILURE; // should not reach
+}
+
+int main(int argc, char* argv[]) {
+ if (fork() == 0) {
+ prctl(PR_SET_PDEATHSIG, SIGHUP);
+ run_service();
+ }
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}