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 #define LOG_TAG "BluetoothQualityReportJni"
18
19 #include <string.h>
20
21 #include <shared_mutex>
22
23 #include "com_android_bluetooth.h"
24 #include "common/init_flags.h"
25 #include "hardware/bt_bqr.h"
26
27 using bluetooth::bqr::BluetoothQualityReportCallbacks;
28 using bluetooth::bqr::BluetoothQualityReportInterface;
29
30 namespace android {
31 static jmethodID method_bqrDeliver;
32
33 static BluetoothQualityReportInterface* sBluetoothQualityReportInterface =
34 nullptr;
35 static std::shared_timed_mutex interface_mutex;
36
37 static jobject mCallbacksObj = nullptr;
38 static std::shared_timed_mutex callbacks_mutex;
39
40 class BluetoothQualityReportCallbacksImpl
41 : public bluetooth::bqr::BluetoothQualityReportCallbacks {
42 public:
43 ~BluetoothQualityReportCallbacksImpl() = default;
44
bqr_delivery_callback(const RawAddress bd_addr,uint8_t lmp_ver,uint16_t lmp_subver,uint16_t manufacturer_id,std::vector<uint8_t> bqr_raw_data)45 void bqr_delivery_callback(const RawAddress bd_addr, uint8_t lmp_ver,
46 uint16_t lmp_subver, uint16_t manufacturer_id,
47 std::vector<uint8_t> bqr_raw_data) override {
48 log::info("");
49 std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
50
51 CallbackEnv sCallbackEnv(__func__);
52 if (!sCallbackEnv.valid()) return;
53 if (method_bqrDeliver == NULL) return;
54 if (mCallbacksObj == nullptr) return;
55
56 ScopedLocalRef<jbyteArray> addr(
57 sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
58 if (!addr.get()) {
59 log::error("Error while allocation byte array for addr");
60 return;
61 }
62
63 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
64 (jbyte*)bd_addr.address);
65
66 ScopedLocalRef<jbyteArray> raw_data(
67 sCallbackEnv.get(), sCallbackEnv->NewByteArray(bqr_raw_data.size()));
68 if (!raw_data.get()) {
69 log::error("Error while allocation byte array for bqr raw data");
70 return;
71 }
72 sCallbackEnv->SetByteArrayRegion(raw_data.get(), 0, bqr_raw_data.size(),
73 (jbyte*)bqr_raw_data.data());
74
75 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_bqrDeliver, addr.get(),
76 (jint)lmp_ver, (jint)lmp_subver,
77 (jint)manufacturer_id, raw_data.get());
78 }
79 };
80
81 static BluetoothQualityReportCallbacksImpl sBluetoothQualityReportCallbacks;
82
initNative(JNIEnv * env,jobject object)83 static void initNative(JNIEnv* env, jobject object) {
84 std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
85 std::unique_lock<std::shared_timed_mutex> callbacks_lock(callbacks_mutex);
86
87 const bt_interface_t* btInf = getBluetoothInterface();
88 if (btInf == nullptr) {
89 log::error("Bluetooth module is not loaded");
90 return;
91 }
92
93 if (sBluetoothQualityReportInterface != nullptr) {
94 log::info(
95 "Cleaning up BluetoothQualityReport Interface before initializing...");
96 sBluetoothQualityReportInterface = nullptr;
97 }
98
99 if (mCallbacksObj != nullptr) {
100 log::info("Cleaning up BluetoothQualityReport callback object");
101 env->DeleteGlobalRef(mCallbacksObj);
102 mCallbacksObj = nullptr;
103 }
104
105 if ((mCallbacksObj = env->NewGlobalRef(object)) == nullptr) {
106 log::error(
107 "Failed to allocate Global Ref for BluetoothQualityReport Callbacks");
108 return;
109 }
110
111 sBluetoothQualityReportInterface =
112 (BluetoothQualityReportInterface*)btInf->get_profile_interface(BT_BQR_ID);
113 if (sBluetoothQualityReportInterface == nullptr) {
114 log::error("Failed to get BluetoothQualityReport Interface");
115 return;
116 }
117
118 sBluetoothQualityReportInterface->init(&sBluetoothQualityReportCallbacks);
119 }
120
cleanupNative(JNIEnv * env,jobject)121 static void cleanupNative(JNIEnv* env, jobject /* object */) {
122 std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
123 std::unique_lock<std::shared_timed_mutex> callbacks_lock(callbacks_mutex);
124
125 const bt_interface_t* btInf = getBluetoothInterface();
126 if (btInf == nullptr) {
127 log::error("Bluetooth module is not loaded");
128 return;
129 }
130
131 if (sBluetoothQualityReportInterface != nullptr) {
132 sBluetoothQualityReportInterface = nullptr;
133 }
134
135 if (mCallbacksObj != nullptr) {
136 env->DeleteGlobalRef(mCallbacksObj);
137 mCallbacksObj = nullptr;
138 }
139 }
140
register_com_android_bluetooth_btservice_BluetoothQualityReport(JNIEnv * env)141 int register_com_android_bluetooth_btservice_BluetoothQualityReport(
142 JNIEnv* env) {
143 const JNINativeMethod methods[] = {
144 {"initNative", "()V", (void*)initNative},
145 {"cleanupNative", "()V", (void*)cleanupNative},
146 };
147 const int result = REGISTER_NATIVE_METHODS(
148 env,
149 "com/android/bluetooth/btservice/BluetoothQualityReportNativeInterface",
150 methods);
151 if (result != 0) {
152 return result;
153 }
154
155 const JNIJavaMethod javaMethods[] = {
156 {"bqrDeliver", "([BIII[B)V", &method_bqrDeliver},
157 };
158 GET_JAVA_METHODS(
159 env,
160 "com/android/bluetooth/btservice/BluetoothQualityReportNativeInterface",
161 javaMethods);
162
163 return 0;
164 }
165 } // namespace android
166