Add API post_on convenience to jni thread

Bug: 163134718
Tag: #refactor
Test: gd/cert/run

Change-Id: I80ae609ad2485eeaabb3b3fe95d6544dd89b6d5f
diff --git a/system/btif/Android.bp b/system/btif/Android.bp
index c6d3fd8..91cbc7a 100644
--- a/system/btif/Android.bp
+++ b/system/btif/Android.bp
@@ -357,6 +357,7 @@
           ":TestMockStack",
           ":TestMockSystemLibfmq",
           ":TestMockUdrv",
+          "test/btif_core_test.cc",
           "test/btif_stack_test.cc",
       ],
       generated_headers: [
@@ -387,4 +388,9 @@
           "libosi",
       ],
       cflags: ["-DBUILDCFG"],
+      sanitize: {
+        address: true,
+        cfi: true,
+        misc_undefined: ["bounds"],
+    },
 }
diff --git a/system/btif/include/btif_common.h b/system/btif/include/btif_common.h
index 51effde..859d8b7 100644
--- a/system/btif/include/btif_common.h
+++ b/system/btif/include/btif_common.h
@@ -25,7 +25,7 @@
 #include <base/bind.h>
 #include <base/location.h>
 #include <hardware/bluetooth.h>
-
+#include <functional>
 #include "abstract_message_loop.h"
 #include "bt_types.h"
 #include "bta/include/bta_api.h"
@@ -155,6 +155,10 @@
                                     base::OnceClosure task);
 extern bool is_on_jni_thread();
 extern btbase::AbstractMessageLoop* get_jni_message_loop();
+
+using BtJniClosure = std::function<void()>;
+void post_on_bt_jni(BtJniClosure closure);
+
 /**
  * This template wraps callback into callback that will be executed on jni
  * thread
diff --git a/system/btif/src/btif_core.cc b/system/btif/src/btif_core.cc
index 560edfe..962d177 100644
--- a/system/btif/src/btif_core.cc
+++ b/system/btif/src/btif_core.cc
@@ -177,6 +177,14 @@
   return jni_thread.message_loop();
 }
 
+static void do_post_on_bt_jni(BtJniClosure closure) { closure(); }
+
+void post_on_bt_jni(BtJniClosure closure) {
+  ASSERT(do_in_jni_thread(FROM_HERE,
+                          base::Bind(do_post_on_bt_jni, std::move(closure))) ==
+         BT_STATUS_SUCCESS);
+}
+
 /*******************************************************************************
  *
  * Function         btif_is_dut_mode
diff --git a/system/btif/test/btif_core_test.cc b/system/btif/test/btif_core_test.cc
new file mode 100644
index 0000000..d3a2aea
--- /dev/null
+++ b/system/btif/test/btif_core_test.cc
@@ -0,0 +1,150 @@
+/*
+ * Copyright 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 <gtest/gtest.h>
+#include <future>
+#include <map>
+
+#include "btif/include/btif_api.h"
+#include "btif/include/btif_common.h"
+
+void set_hal_cbacks(bt_callbacks_t* callbacks);
+
+namespace {
+
+auto timeout_time = std::chrono::seconds(3);
+
+std::map<std::string, std::function<void()>> callback_map_;
+#define TESTCB                                             \
+  if (callback_map_.find(__func__) != callback_map_.end()) \
+    callback_map_[__func__]();
+
+void adapter_state_changed_callback(bt_state_t state) {}
+void adapter_properties_callback(bt_status_t status, int num_properties,
+                                 bt_property_t* properties) {}
+void remote_device_properties_callback(bt_status_t status, RawAddress* bd_addr,
+                                       int num_properties,
+                                       bt_property_t* properties) {}
+void device_found_callback(int num_properties, bt_property_t* properties) {}
+void discovery_state_changed_callback(bt_discovery_state_t state) {}
+void pin_request_callback(RawAddress* remote_bd_addr, bt_bdname_t* bd_name,
+                          uint32_t cod, bool min_16_digit) {}
+void ssp_request_callback(RawAddress* remote_bd_addr, bt_bdname_t* bd_name,
+                          uint32_t cod, bt_ssp_variant_t pairing_variant,
+                          uint32_t pass_key) {}
+void bond_state_changed_callback(bt_status_t status, RawAddress* remote_bd_addr,
+                                 bt_bond_state_t state) {}
+void acl_state_changed_callback(bt_status_t status, RawAddress* remote_bd_addr,
+                                bt_acl_state_t state,
+                                bt_hci_error_code_t hci_reason) {}
+void link_quality_report_callback(uint64_t timestamp, int report_id, int rssi,
+                                  int snr, int retransmission_count,
+                                  int packets_not_receive_count,
+                                  int negative_acknowledgement_count) {}
+void callback_thread_event(bt_cb_thread_evt evt) { TESTCB; }
+void dut_mode_recv_callback(uint16_t opcode, uint8_t* buf, uint8_t len) {}
+void le_test_mode_callback(bt_status_t status, uint16_t num_packets) {}
+void energy_info_callback(bt_activity_energy_info* energy_info,
+                          bt_uid_traffic_t* uid_data) {}
+void generate_local_oob_data_callback(tBT_TRANSPORT transport,
+                                      bt_oob_data_t oob_data) {}
+#undef TESTCB
+
+bt_callbacks_t callbacks = {
+    .size = sizeof(bt_callbacks_t),
+    .adapter_state_changed_cb = adapter_state_changed_callback,
+    .adapter_properties_cb = adapter_properties_callback,
+    .remote_device_properties_cb = remote_device_properties_callback,
+    .device_found_cb = device_found_callback,
+    .discovery_state_changed_cb = discovery_state_changed_callback,
+    .pin_request_cb = pin_request_callback,
+    .ssp_request_cb = ssp_request_callback,
+    .bond_state_changed_cb = bond_state_changed_callback,
+    .acl_state_changed_cb = acl_state_changed_callback,
+    .thread_evt_cb = callback_thread_event,
+    .dut_mode_recv_cb = dut_mode_recv_callback,
+    .le_test_mode_cb = le_test_mode_callback,
+    .energy_info_cb = energy_info_callback,
+    .link_quality_report_cb = link_quality_report_callback,
+    .generate_local_oob_data_cb = generate_local_oob_data_callback,
+};
+
+}  // namespace
+
+class BtifCoreTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    callback_map_.clear();
+    set_hal_cbacks(&callbacks);
+
+    auto promise = std::promise<void>();
+    auto future = promise.get_future();
+    callback_map_["callback_thread_event"] = [&promise]() {
+      promise.set_value();
+    };
+    btif_init_bluetooth();
+    ASSERT_EQ(std::future_status::ready, future.wait_for(timeout_time));
+    callback_map_.erase("callback_thread_event");
+  }
+
+  void TearDown() override {
+    auto promise = std::promise<void>();
+    auto future = promise.get_future();
+    callback_map_["callback_thread_event"] = [&promise]() {
+      promise.set_value();
+    };
+    btif_cleanup_bluetooth();
+    ASSERT_EQ(std::future_status::ready, future.wait_for(timeout_time));
+    callback_map_.erase("callback_thread_event");
+  }
+};
+
+std::promise<int> promise0;
+void callback0(int val) { promise0.set_value(val); }
+
+TEST_F(BtifCoreTest, test_post_on_bt_simple0) {
+  const int val = 123;
+  promise0 = std::promise<int>();
+  std::future<int> future0 = promise0.get_future();
+  post_on_bt_jni([=]() { callback0(val); });
+  ASSERT_EQ(std::future_status::ready, future0.wait_for(timeout_time));
+  ASSERT_EQ(val, future0.get());
+}
+
+TEST_F(BtifCoreTest, test_post_on_bt_jni_simple1) {
+  std::promise<void> promise;
+  std::future<void> future = promise.get_future();
+  post_on_bt_jni([=, &promise]() { promise.set_value(); });
+  ASSERT_EQ(std::future_status::ready, future.wait_for(timeout_time));
+}
+
+TEST_F(BtifCoreTest, test_post_on_bt_jni_simple2) {
+  std::promise<void> promise;
+  std::future<void> future = promise.get_future();
+  BtJniClosure closure = [&promise]() { promise.set_value(); };
+  post_on_bt_jni(closure);
+  ASSERT_EQ(std::future_status::ready, future.wait_for(timeout_time));
+}
+
+TEST_F(BtifCoreTest, test_post_on_bt_jni_simple3) {
+  const int val = 456;
+  std::promise<int> promise;
+  auto future = promise.get_future();
+  BtJniClosure closure = [&promise, val]() { promise.set_value(val); };
+  post_on_bt_jni(closure);
+  ASSERT_EQ(std::future_status::ready, future.wait_for(timeout_time));
+  ASSERT_EQ(val, future.get());
+}