• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 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 "module_jniloop_unittest.h"
18 
19 #include <base/callback.h>
20 #include <base/functional/bind.h>
21 #include <base/location.h>
22 #include <base/threading/platform_thread.h>
23 #include <sys/syscall.h>
24 
25 #include <string>
26 
27 #include "btif/include/btif_jni_task.h"
28 #include "gtest/gtest.h"
29 #include "module.h"
30 #include "os/handler.h"
31 #include "os/thread.h"
32 
33 using namespace bluetooth;
34 
35 namespace {
36 constexpr int sync_timeout_in_ms = 3000;
37 
38 std::promise<pid_t> external_function_promise;
39 std::promise<pid_t> private_impl_promise;
40 std::promise<pid_t> protected_method_promise;
41 
42 }  // namespace
43 
44 // Global function with C linkage
external_function_jni(int,double,char)45 void external_function_jni(int /* a */, double /* b */, char /* c */) {
46   external_function_promise.set_value(base::PlatformThread::CurrentId());
47 }
48 
49 // Module private implementation that is inaccessible externally
50 struct TestJniModule::PrivateImpl : public ModuleJniloop {
51   const int kMaxTestModuleRecurseDepth = 10;
52 
privateCallableMethodTestJniModule::PrivateImpl53   void privateCallableMethod(int /* a */, double /* b */, char /* c */) {
54     private_impl_promise.set_value(base::PlatformThread::CurrentId());
55   }
56 
repostMethodTestTestJniModule::PrivateImpl57   void repostMethodTest(int /* a */, double /* b */, char /* c */) {
58     private_impl_promise.set_value(base::PlatformThread::CurrentId());
59   }
60 
privateCallableRepostMethodTestJniModule::PrivateImpl61   void privateCallableRepostMethod(
62       std::shared_ptr<TestJniModule::PrivateImpl> ptr, int a, double b, char c) {
63     PostMethodOnJni(ptr, &PrivateImpl::repostMethodTest, a, b, c);
64   }
65 
privateCallableRecursiveMethodTestJniModule::PrivateImpl66   void privateCallableRecursiveMethod(
67       std::shared_ptr<TestJniModule::PrivateImpl> ptr, int depth, double b, char c) {
68     if (depth > kMaxTestModuleRecurseDepth) {
69       private_impl_promise.set_value(base::PlatformThread::CurrentId());
70       return;
71     }
72     PostMethodOnJni(ptr, &PrivateImpl::privateCallableRecursiveMethod, ptr, depth + 1, b, c);
73   }
74 };
75 
76 // Protected module method executed on handler
call_on_handler_protected_method(int loop_tid,int a,int b,int c)77 void TestJniModule::call_on_handler_protected_method(int loop_tid, int a, int b, int c) {
78   protected_method_promise = std::promise<pid_t>();
79   auto future = protected_method_promise.get_future();
80   CallOn(this, &TestJniModule::protected_method, a, b, c);
81   ASSERT_EQ(future.wait_for(std::chrono::seconds(3)), std::future_status::ready);
82   ASSERT_EQ(future.get(), loop_tid);
83 }
84 
85 // Global external function executed on jni loop
call_on_jni_external_function(int loop_tid,int a,double b,char c)86 void TestJniModule::call_on_jni_external_function(int loop_tid, int a, double b, char c) {
87   external_function_promise = std::promise<pid_t>();
88   auto future = external_function_promise.get_future();
89   PostFunctionOnJni(&external_function_jni, a, b, c);
90   ASSERT_EQ(future.wait_for(std::chrono::seconds(3)), std::future_status::ready);
91   ASSERT_EQ(future.get(), loop_tid);
92 }
93 
94 // Private implementation method executed on main loop
call_on_jni(int loop_tid,int a,int b,int c)95 void TestJniModule::call_on_jni(int loop_tid, int a, int b, int c) {
96   private_impl_promise = std::promise<pid_t>();
97   auto future = private_impl_promise.get_future();
98   PostMethodOnJni(pimpl_, &TestJniModule::PrivateImpl::privateCallableMethod, a, b, c);
99   ASSERT_EQ(future.wait_for(std::chrono::seconds(3)), std::future_status::ready);
100   ASSERT_EQ(future.get(), loop_tid);
101 }
102 
103 // Private implementation method executed on jni loop and reposted
call_on_jni_repost(int loop_tid,int a,int b,int c)104 void TestJniModule::call_on_jni_repost(int loop_tid, int a, int b, int c) {
105   private_impl_promise = std::promise<pid_t>();
106   auto future = private_impl_promise.get_future();
107   PostMethodOnJni(
108       pimpl_, &TestJniModule::PrivateImpl::privateCallableRepostMethod, pimpl_, a, b, c);
109   ASSERT_EQ(future.wait_for(std::chrono::seconds(3)), std::future_status::ready);
110   ASSERT_EQ(future.get(), loop_tid);
111 }
112 
113 // Private implementation method executed on jni loop recursively
call_on_jni_recurse(int loop_tid,int depth,int b,int c)114 void TestJniModule::call_on_jni_recurse(int loop_tid, int depth, int b, int c) {
115   private_impl_promise = std::promise<pid_t>();
116   auto future = private_impl_promise.get_future();
117   PostMethodOnJni(
118       pimpl_, &TestJniModule::PrivateImpl::privateCallableRecursiveMethod, pimpl_, depth, b, c);
119   ASSERT_EQ(future.wait_for(std::chrono::seconds(3)), std::future_status::ready);
120   ASSERT_EQ(future.get(), loop_tid);
121 }
122 
protected_method(int,int,int)123 void TestJniModule::protected_method(int /* a */, int /* b */, int /* c */) {
124   protected_method_promise.set_value(base::PlatformThread::CurrentId());
125 }
126 
IsStarted() const127 bool TestJniModule::IsStarted() const {
128   return pimpl_ != nullptr;
129 }
130 
Start()131 void TestJniModule::Start() {
132   ASSERT_FALSE(IsStarted());
133   pimpl_ = std::make_shared<TestJniModule::PrivateImpl>();
134 }
135 
Stop()136 void TestJniModule::Stop() {
137   ASSERT_TRUE(IsStarted());
138   pimpl_.reset();
139 }
140 
ToString() const141 std::string TestJniModule::ToString() const {
142   return std::string(__func__);
143 }
144 
145 const bluetooth::ModuleFactory TestJniModule::Factory =
__anonbb8b63ef0202() 146     bluetooth::ModuleFactory([]() { return new TestJniModule(); });
147 
148 //
149 // Module GDx Testing Below
150 //
151 class ModuleGdxJniTest : public ::testing::Test {
152  protected:
SetUp()153   void SetUp() override {
154     test_framework_tid_ = base::PlatformThread::CurrentId();
155     module_ = new TestJniModule();
156     jni_thread_startup();
157     jniloop_tid_ = get_jniloop_tid();
158   }
159 
TearDown()160   void TearDown() override {
161     sync_jni_handler();
162     jni_thread_shutdown();
163     delete module_;
164   }
165 
sync_jni_handler()166   void sync_jni_handler() {
167     std::promise promise = std::promise<void>();
168     std::future future = promise.get_future();
169     post_on_bt_jni([&promise]() { promise.set_value(); });
170     future.wait_for(std::chrono::milliseconds(sync_timeout_in_ms));
171   };
172 
get_jniloop_tid()173   static pid_t get_jniloop_tid() {
174     std::promise<pid_t> pid_promise = std::promise<pid_t>();
175     auto future = pid_promise.get_future();
176     post_on_bt_jni([&pid_promise]() { pid_promise.set_value(base::PlatformThread::CurrentId()); });
177     return future.get();
178   }
179 
180   pid_t test_framework_tid_{-1};
181   pid_t jniloop_tid_{-1};
182   TestModuleRegistry module_registry_;
183   TestJniModule* module_;
184 };
185 
186 class ModuleGdxWithJniStackTest : public ModuleGdxJniTest {
187  protected:
SetUp()188   void SetUp() override {
189     ModuleGdxJniTest::SetUp();
190     module_registry_.InjectTestModule(&TestJniModule::Factory, module_ /* pass ownership */);
191     module_ = nullptr;  // ownership is passed
192     handler_tid_ = get_handler_tid(module_registry_.GetTestModuleHandler(&TestJniModule::Factory));
193   }
194 
get_handler_tid(os::Handler * handler)195   static pid_t get_handler_tid(os::Handler* handler) {
196     std::promise<pid_t> handler_tid_promise = std::promise<pid_t>();
197     std::future<pid_t> future = handler_tid_promise.get_future();
198     handler->Post(common::BindOnce(
199         [](std::promise<pid_t> promise) { promise.set_value(base::PlatformThread::CurrentId()); },
200         std::move(handler_tid_promise)));
201     return future.get();
202   }
203 
TearDown()204   void TearDown() override {
205     module_registry_.StopAll();
206     ModuleGdxJniTest::TearDown();
207   }
208 
Mod()209   TestJniModule* Mod() {
210     return module_registry_.GetModuleUnderTest<TestJniModule>();
211   }
212 
213   pid_t handler_tid_{-1};
214 };
215 
TEST_F(ModuleGdxJniTest,nop)216 TEST_F(ModuleGdxJniTest, nop) {}
217 
TEST_F(ModuleGdxJniTest,lifecycle)218 TEST_F(ModuleGdxJniTest, lifecycle) {
219   ::bluetooth::os::Thread* thread =
220       new bluetooth::os::Thread("Name", bluetooth::os::Thread::Priority::REAL_TIME);
221   ASSERT_FALSE(module_registry_.IsStarted<TestJniModule>());
222   module_registry_.Start<TestJniModule>(thread);
223   ASSERT_TRUE(module_registry_.IsStarted<TestJniModule>());
224   module_registry_.StopAll();
225   ASSERT_FALSE(module_registry_.IsStarted<TestJniModule>());
226   delete thread;
227 }
228 
TEST_F(ModuleGdxWithJniStackTest,call_on_handler_protected_method)229 TEST_F(ModuleGdxWithJniStackTest, call_on_handler_protected_method) {
230   Mod()->call_on_handler_protected_method(handler_tid_, 1, 2, 3);
231 }
232 
TEST_F(ModuleGdxWithJniStackTest,test_call_on_jni)233 TEST_F(ModuleGdxWithJniStackTest, test_call_on_jni) {
234   Mod()->call_on_jni(jniloop_tid_, 1, 2, 3);
235 }
236 
TEST_F(ModuleGdxWithJniStackTest,test_call_external_function)237 TEST_F(ModuleGdxWithJniStackTest, test_call_external_function) {
238   Mod()->call_on_jni_external_function(jniloop_tid_, 1, 2.3, 'c');
239 }
240 
TEST_F(ModuleGdxWithJniStackTest,test_call_on_jni_repost)241 TEST_F(ModuleGdxWithJniStackTest, test_call_on_jni_repost) {
242   Mod()->call_on_jni_repost(jniloop_tid_, 1, 2, 3);
243 }
244 
TEST_F(ModuleGdxWithJniStackTest,test_call_on_jni_recurse)245 TEST_F(ModuleGdxWithJniStackTest, test_call_on_jni_recurse) {
246   Mod()->call_on_jni_recurse(jniloop_tid_, 1, 2, 3);
247 }
248