1 /*
2  * Copyright (C) 2018 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 #pragma once
18 
19 #include <android/binder_auto_utils.h>
20 #include <android/binder_ibinder.h>
21 #include <gtest/gtest.h>
22 #include <nativetesthelper_jni/utils.h>
23 
24 #include <functional>
25 
26 // Helpers for testing
27 
28 template <typename T>
29 static inline ::testing::AssertionResult isOk(T) = delete;
30 
31 template <>
isOk(::ndk::ScopedAStatus t)32 inline ::testing::AssertionResult isOk(::ndk::ScopedAStatus t) {
33   if (AStatus_isOk(t.get())) {
34     return ::testing::AssertionSuccess();
35   } else {
36     return ::testing::AssertionFailure()
37            << "exception: " << AStatus_getExceptionCode(t.get())
38            << " service specific: " << AStatus_getServiceSpecificError(t.get())
39            << " status: " << AStatus_getStatus(t.get());
40   }
41 }
42 
43 template <>
isOk(binder_status_t t)44 inline ::testing::AssertionResult isOk(binder_status_t t) {
45   if (t == STATUS_OK) {
46     return ::testing::AssertionSuccess();
47   }
48   return ::testing::AssertionFailure() << "Status: " << t;
49 }
50 
ContainsSubstring(const std::string & s,const std::string & ss)51 inline ::testing::AssertionResult ContainsSubstring(const std::string& s, const std::string& ss) {
52   if (s.find(ss) != std::string::npos) {
53     return ::testing::AssertionSuccess();
54   } else {
55     return ::testing::AssertionFailure()
56            << "String: '" << s << "' does not contain substring: " << ss;
57   }
58 }
59 
60 #define EXPECT_OK(THING) EXPECT_TRUE(isOk(THING))
61 #define ASSERT_OK(THING) ASSERT_TRUE(isOk(THING))
62 
63 // placeholder
64 constexpr transaction_code_t kCode = +1 + 918;
65 
66 // Usually, things at this level would be generated by the aidl compiler. This
67 // class is merely to make testing the API easier.
68 
69 struct SampleData;
70 
71 typedef std::function<void(SampleData*)> OnDestroyFunc;
72 typedef std::function<binder_status_t(transaction_code_t code,
73                                       const AParcel* in, AParcel* out)>
74     OnTransactFunc;
75 
76 typedef std::function<binder_status_t(AParcel*)> WriteParcel;
77 typedef std::function<binder_status_t(const AParcel*)> ReadParcel;
78 
WriteNothingToParcel(AParcel *)79 static inline binder_status_t WriteNothingToParcel(AParcel*) {
80   return STATUS_OK;
81 }
ReadNothingFromParcel(const AParcel *)82 static inline binder_status_t ReadNothingFromParcel(const AParcel*) {
83   return STATUS_OK;
84 }
85 
86 // There is an assert instances of this class are destroyed in NdkBinderTest
87 struct ThisShouldBeDestroyed {
88   static size_t numInstances();
89 
90   ThisShouldBeDestroyed();
91   virtual ~ThisShouldBeDestroyed();
92 };
93 
94 struct SampleData : ThisShouldBeDestroyed {
95   static const char* kDescriptor;
96   static const AIBinder_Class* kClass;
97   static const AIBinder_Class* kAnotherClassWithSameDescriptor;
98 
99   static const char* kAnotherDescriptor;
100   static const AIBinder_Class* kAnotherClass;
101 
102   SampleData(const OnTransactFunc& oT = nullptr,
103              const OnDestroyFunc& oD = nullptr)
onTransactSampleData104       : onTransact(oT), onDestroy(oD) {}
105 
106   // This is called when the class is transacted on if non-null.
107   // Otherwise, STATUS_FAILED_TRANSACTION is returned.
108   OnTransactFunc onTransact;
109 
110   // This is called when the class is destroyed if non-null.
111   OnDestroyFunc onDestroy;
112 
113   // Automatically updated by this class whenever a transaction is received.
114   int numberTransactions = 0;
115 
116   __attribute__((warn_unused_result)) static AIBinder* newBinder(
117       OnTransactFunc onTransact = nullptr, OnDestroyFunc onDestroy = nullptr) {
118     SampleData* data = new SampleData(onTransact, onDestroy);
119     return AIBinder_new(kClass, static_cast<void*>(data));
120   };
121 
122   // Helper method to simplify transaction logic
123   static binder_status_t transact(AIBinder* binder, transaction_code_t code,
124                                   WriteParcel writeFunc = WriteNothingToParcel,
125                                   ReadParcel readFunc = ReadNothingFromParcel,
126                                   binder_flags_t flags = 0) {
127     AParcel* in;
128     binder_status_t status = AIBinder_prepareTransaction(binder, &in);
129     if (status != STATUS_OK) return status;
130 
131     status = writeFunc(in);
132     if (status != STATUS_OK) {
133       AParcel_delete(in);
134       return status;
135     }
136 
137     AParcel* out;
138     status = AIBinder_transact(binder, code, &in, &out, flags);
139     if (status != STATUS_OK) return status;
140 
141     status = readFunc(out);
142     AParcel_delete(out);
143 
144     return status;
145   }
146 };
147 
ExpectLifetimeTransactions(size_t count)148 static inline OnDestroyFunc ExpectLifetimeTransactions(size_t count) {
149   return [count](SampleData* data) {
150     EXPECT_EQ(count, data->numberTransactions)
151         << "Expected " << count
152         << " transaction(s), but over the lifetime of this object, it received "
153         << data->numberTransactions;
154   };
155 }
156 
TransactionsReturn(binder_status_t result)157 static inline OnTransactFunc TransactionsReturn(binder_status_t result) {
158   return
159       [result](transaction_code_t, const AParcel*, AParcel*) { return result; };
160 }
161 
162 class NdkBinderTest : public ::testing::Test {
163  public:
SetUp()164   void SetUp() override { instances = ThisShouldBeDestroyed::numInstances(); }
TearDown()165   void TearDown() override {
166     EXPECT_EQ(instances, ThisShouldBeDestroyed::numInstances());
167   }
168 
169  private:
170   size_t instances = 0;
171 };
172 
173 JNIEnv* GetEnv();
174 jobject callStaticJavaMethodForObject(JNIEnv* env, const std::string& clazz,
175                                       const std::string& method, const std::string& type);
176