1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <aidl/android/aidl/test/trunk/BnTrunkStableTest.h>
18 #include <aidl/android/aidl/test/trunk/ITrunkStableTest.h>
19 #include <android/binder_auto_utils.h>
20 #include <android/binder_manager.h>
21 #include <binder/ProcessState.h>
22 #include <gtest/gtest.h>
23 
24 #ifdef AIDL_USE_UNFROZEN
25 constexpr bool kUseUnfrozen = true;
26 #else
27 constexpr bool kUseUnfrozen = false;
28 #endif
29 
30 using aidl::android::aidl::test::trunk::ITrunkStableTest;
31 using ndk::ScopedAStatus;
32 using MyParcelable = aidl::android::aidl::test::trunk::ITrunkStableTest::MyParcelable;
33 using MyOtherParcelable = aidl::android::aidl::test::trunk::ITrunkStableTest::MyOtherParcelable;
34 using MyEnum = aidl::android::aidl::test::trunk::ITrunkStableTest::MyEnum;
35 using MyUnion = aidl::android::aidl::test::trunk::ITrunkStableTest::MyUnion;
36 
37 class TrunkInterfaceTest : public testing::Test {
38  public:
SetUp()39   void SetUp() override {
40     android::ProcessState::self()->setThreadPoolMaxThreadCount(1);
41     android::ProcessState::self()->startThreadPool();
42     ndk::SpAIBinder binder =
43         ndk::SpAIBinder(AServiceManager_waitForService(ITrunkStableTest::descriptor));
44     service = ITrunkStableTest::fromBinder(binder);
45     ASSERT_NE(nullptr, service);
46   }
47 
48   std::shared_ptr<ITrunkStableTest> service;
49 };
50 
TEST_F(TrunkInterfaceTest,getInterfaceVersion)51 TEST_F(TrunkInterfaceTest, getInterfaceVersion) {
52   // TODO(b/292539129) this should be done with an annotation instead of ifdefs
53   // We have to match on a single char with #if, even though it is
54   // really "enabled"/"disabled"
55   int32_t ver = 0;
56   auto status = service->getInterfaceVersion(&ver);
57   ASSERT_TRUE(status.isOk());
58   if (kUseUnfrozen) {
59     EXPECT_EQ(2, ver);
60     // Check the local version as well
61     EXPECT_EQ(2, ITrunkStableTest::version);
62   } else {
63     EXPECT_EQ(1, ver);
64     // Check the local version as well
65     EXPECT_EQ(1, ITrunkStableTest::version);
66   }
67 }
68 
TEST_F(TrunkInterfaceTest,getInterfaceHash)69 TEST_F(TrunkInterfaceTest, getInterfaceHash) {
70   std::string hash;
71   std::string localHash;
72   auto status = service->getInterfaceHash(&hash);
73   ASSERT_TRUE(status.isOk());
74   if (kUseUnfrozen) {
75     EXPECT_EQ("notfrozen", hash);
76     // Check the local hash as well
77     EXPECT_EQ("notfrozen", ITrunkStableTest::hash);
78   } else {
79     EXPECT_EQ("88311b9118fb6fe9eff4a2ca19121de0587f6d5f", hash);
80     // Check the local hash as well
81     EXPECT_EQ("88311b9118fb6fe9eff4a2ca19121de0587f6d5f", ITrunkStableTest::hash);
82   }
83 }
84 
85 // `c` is a new field that isn't read from the reply parcel
TEST_F(TrunkInterfaceTest,repeatParcelable)86 TEST_F(TrunkInterfaceTest, repeatParcelable) {
87   MyParcelable in, out;
88   in.a = 14;
89   in.b = 15;
90   in.c = 16;
91 
92   auto status = service->repeatParcelable(in, &out);
93   ASSERT_TRUE(status.isOk()) << status;
94   if (kUseUnfrozen) {
95     EXPECT_EQ(in.a, out.a);
96     EXPECT_EQ(in.b, out.b);
97     EXPECT_EQ(in.c, out.c);
98   } else {
99     EXPECT_EQ(in.a, out.a);
100     EXPECT_EQ(in.b, out.b);
101     EXPECT_NE(in.c, out.c);
102     EXPECT_EQ(0, out.c);
103   }
104 }
105 
106 // repeatOtherParcelable is a new API that isn't implemented
TEST_F(TrunkInterfaceTest,repeatOtherParcelable)107 TEST_F(TrunkInterfaceTest, repeatOtherParcelable) {
108   MyOtherParcelable in, out;
109   in.a = 14;
110   in.b = 15;
111 
112   auto status = service->repeatOtherParcelable(in, &out);
113   if (kUseUnfrozen) {
114     ASSERT_TRUE(status.isOk()) << status;
115     EXPECT_EQ(in.a, out.a);
116     EXPECT_EQ(in.b, out.b);
117   } else {
118     EXPECT_FALSE(status.isOk()) << status;
119     EXPECT_EQ(STATUS_UNKNOWN_TRANSACTION, status.getStatus()) << status;
120   }
121 }
122 
123 // enums aren't handled differently.
TEST_F(TrunkInterfaceTest,repeatEnum)124 TEST_F(TrunkInterfaceTest, repeatEnum) {
125   MyEnum in = MyEnum::THREE;
126   MyEnum out = MyEnum::ZERO;
127 
128   auto status = service->repeatEnum(in, &out);
129   ASSERT_TRUE(status.isOk()) << status;
130   EXPECT_EQ(in, out);
131 }
132 
133 // `c` is a new field that causes a failure if used
134 // `b` is from V1 and will cause no failure
TEST_F(TrunkInterfaceTest,repeatUnion)135 TEST_F(TrunkInterfaceTest, repeatUnion) {
136   MyUnion in_ok = MyUnion::make<MyUnion::b>(13);
137   MyUnion in_test = MyUnion::make<MyUnion::c>(12);
138   MyUnion out;
139 
140   auto status = service->repeatUnion(in_ok, &out);
141   ASSERT_TRUE(status.isOk()) << status;
142   EXPECT_EQ(in_ok, out);
143 
144   status = service->repeatUnion(in_test, &out);
145   if (kUseUnfrozen) {
146     ASSERT_TRUE(status.isOk()) << status;
147     EXPECT_EQ(in_test, out);
148   } else {
149     ASSERT_FALSE(status.isOk()) << status;
150     EXPECT_NE(in_test, out);
151   }
152 }
153 
154 class MyCallback : public ITrunkStableTest::BnMyCallback {
155  public:
MyCallback()156   MyCallback() {}
157   virtual ~MyCallback() = default;
158 
repeatParcelable(const MyParcelable & input,MyParcelable * _aidl_return)159   ScopedAStatus repeatParcelable(const MyParcelable& input, MyParcelable* _aidl_return) override {
160     *_aidl_return = input;
161     repeatParcelableCalled = true;
162     return ScopedAStatus::ok();
163   }
repeatEnum(MyEnum input,MyEnum * _aidl_return)164   ScopedAStatus repeatEnum(MyEnum input, MyEnum* _aidl_return) override {
165     *_aidl_return = input;
166     repeatEnumCalled = true;
167     return ScopedAStatus::ok();
168   }
repeatUnion(const MyUnion & input,MyUnion * _aidl_return)169   ScopedAStatus repeatUnion(const MyUnion& input, MyUnion* _aidl_return) override {
170     *_aidl_return = input;
171     repeatUnionCalled = true;
172     return ScopedAStatus::ok();
173   }
174 
repeatOtherParcelable(const MyOtherParcelable & input,MyOtherParcelable * _aidl_return)175   ScopedAStatus repeatOtherParcelable(const MyOtherParcelable& input,
176                                       MyOtherParcelable* _aidl_return) override {
177     *_aidl_return = input;
178     repeatOtherParcelableCalled = true;
179     return ScopedAStatus::ok();
180   }
181 
182   bool repeatParcelableCalled = false;
183   bool repeatEnumCalled = false;
184   bool repeatUnionCalled = false;
185   bool repeatOtherParcelableCalled = false;
186 };
187 
188 // repeatOtherParcelable is new in V2, so it won't be called
TEST_F(TrunkInterfaceTest,callMyCallback)189 TEST_F(TrunkInterfaceTest, callMyCallback) {
190   std::shared_ptr<MyCallback> cb = ndk::SharedRefBase::make<MyCallback>();
191 
192   auto status = service->callMyCallback(cb);
193   ASSERT_TRUE(status.isOk()) << status;
194   if (kUseUnfrozen) {
195     EXPECT_TRUE(cb->repeatParcelableCalled);
196     EXPECT_TRUE(cb->repeatEnumCalled);
197     EXPECT_TRUE(cb->repeatUnionCalled);
198     EXPECT_TRUE(cb->repeatOtherParcelableCalled);
199   } else {
200     EXPECT_TRUE(cb->repeatParcelableCalled);
201     EXPECT_TRUE(cb->repeatEnumCalled);
202     EXPECT_TRUE(cb->repeatUnionCalled);
203     EXPECT_FALSE(cb->repeatOtherParcelableCalled);
204   }
205 }
206