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