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