1 /*
2 * Copyright (C) 2012 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 "BluetoothPanServiceJni"
18
19 #include <string.h>
20
21 #include "com_android_bluetooth.h"
22 #include "hardware/bt_pan.h"
23
24 namespace android {
25
26 static jmethodID method_onConnectStateChanged;
27 static jmethodID method_onControlStateChanged;
28
29 static const btpan_interface_t* sPanIf = NULL;
30 static jobject mCallbacksObj = NULL;
31
marshall_bda(const RawAddress * bd_addr)32 static jbyteArray marshall_bda(const RawAddress* bd_addr) {
33 CallbackEnv sCallbackEnv(__func__);
34 if (!sCallbackEnv.valid()) return NULL;
35
36 jbyteArray addr = sCallbackEnv->NewByteArray(sizeof(RawAddress));
37 if (!addr) {
38 log::error("Fail to new jbyteArray bd addr");
39 return NULL;
40 }
41 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(RawAddress),
42 (jbyte*)bd_addr);
43 return addr;
44 }
45
control_state_callback(btpan_control_state_t state,int local_role,bt_status_t error,const char * ifname)46 static void control_state_callback(btpan_control_state_t state, int local_role,
47 bt_status_t error, const char* ifname) {
48 log::debug("state:{}, local_role:{}, ifname:{}", state, local_role, ifname);
49 if (mCallbacksObj == NULL) {
50 log::error("Callbacks Obj is NULL");
51 return;
52 }
53 CallbackEnv sCallbackEnv(__func__);
54 if (!sCallbackEnv.valid()) return;
55 ScopedLocalRef<jstring> js_ifname(sCallbackEnv.get(),
56 sCallbackEnv->NewStringUTF(ifname));
57 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onControlStateChanged,
58 (jint)local_role, (jint)state, (jint)error,
59 js_ifname.get());
60 }
61
connection_state_callback(btpan_connection_state_t state,bt_status_t error,const RawAddress * bd_addr,int local_role,int remote_role)62 static void connection_state_callback(btpan_connection_state_t state,
63 bt_status_t error,
64 const RawAddress* bd_addr, int local_role,
65 int remote_role) {
66 log::debug("state:{}, local_role:{}, remote_role:{}", state, local_role,
67 remote_role);
68 if (mCallbacksObj == NULL) {
69 log::error("Callbacks Obj is NULL");
70 return;
71 }
72 CallbackEnv sCallbackEnv(__func__);
73 if (!sCallbackEnv.valid()) return;
74 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
75 if (!addr.get()) {
76 log::error("Fail to new jbyteArray bd addr for PAN channel state");
77 return;
78 }
79 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectStateChanged,
80 addr.get(), (jint)state, (jint)error,
81 (jint)local_role, (jint)remote_role);
82 }
83
84 static btpan_callbacks_t sBluetoothPanCallbacks = {
85 sizeof(sBluetoothPanCallbacks), control_state_callback,
86 connection_state_callback};
87
88 // Define native functions
89 static const bt_interface_t* btIf;
90
initializeNative(JNIEnv * env,jobject object)91 static void initializeNative(JNIEnv* env, jobject object) {
92 log::debug("Initialize pan");
93 if (btIf) return;
94
95 btIf = getBluetoothInterface();
96 if (btIf == NULL) {
97 log::error("Bluetooth module is not loaded");
98 return;
99 }
100
101 if (sPanIf != NULL) {
102 log::warn("Cleaning up Bluetooth PAN Interface before initializing...");
103 sPanIf->cleanup();
104 sPanIf = NULL;
105 }
106
107 if (mCallbacksObj != NULL) {
108 log::warn("Cleaning up Bluetooth PAN callback object");
109 env->DeleteGlobalRef(mCallbacksObj);
110 mCallbacksObj = NULL;
111 }
112
113 sPanIf = (btpan_interface_t*)btIf->get_profile_interface(BT_PROFILE_PAN_ID);
114 if (sPanIf == NULL) {
115 log::error("Failed to get Bluetooth PAN Interface");
116 return;
117 }
118
119 mCallbacksObj = env->NewGlobalRef(object);
120
121 bt_status_t status = sPanIf->init(&sBluetoothPanCallbacks);
122 if (status != BT_STATUS_SUCCESS) {
123 log::error("Failed to initialize Bluetooth PAN, status: {}",
124 bt_status_text(status));
125 sPanIf = NULL;
126 if (mCallbacksObj != NULL) {
127 log::warn(
128 "initialization failed: Cleaning up Bluetooth PAN callback object");
129 env->DeleteGlobalRef(mCallbacksObj);
130 mCallbacksObj = NULL;
131 }
132 return;
133 }
134 }
135
cleanupNative(JNIEnv * env,jobject)136 static void cleanupNative(JNIEnv* env, jobject /* object */) {
137 log::debug("Cleanup pan");
138 if (!btIf) return;
139
140 if (sPanIf != NULL) {
141 log::warn("Cleaning up Bluetooth PAN Interface...");
142 sPanIf->cleanup();
143 sPanIf = NULL;
144 }
145
146 if (mCallbacksObj != NULL) {
147 log::warn("Cleaning up Bluetooth PAN callback object");
148 env->DeleteGlobalRef(mCallbacksObj);
149 mCallbacksObj = NULL;
150 }
151 btIf = NULL;
152 }
153
connectPanNative(JNIEnv * env,jobject,jbyteArray address,jint src_role,jint dest_role)154 static jboolean connectPanNative(JNIEnv* env, jobject /* object */,
155 jbyteArray address, jint src_role,
156 jint dest_role) {
157 log::debug("Connect pan");
158 if (!sPanIf) return JNI_FALSE;
159
160 jbyte* addr = env->GetByteArrayElements(address, NULL);
161 if (!addr) {
162 log::error("Bluetooth device address null");
163 return JNI_FALSE;
164 }
165
166 jboolean ret = JNI_TRUE;
167 bt_status_t status = sPanIf->connect((RawAddress*)addr, src_role, dest_role);
168 if (status != BT_STATUS_SUCCESS) {
169 log::error("Failed PAN channel connection, status: {}",
170 bt_status_text(status));
171 ret = JNI_FALSE;
172 }
173 env->ReleaseByteArrayElements(address, addr, 0);
174
175 return ret;
176 }
177
disconnectPanNative(JNIEnv * env,jobject,jbyteArray address)178 static jboolean disconnectPanNative(JNIEnv* env, jobject /* object */,
179 jbyteArray address) {
180 log::debug("Disconnects pan");
181 if (!sPanIf) return JNI_FALSE;
182
183 jbyte* addr = env->GetByteArrayElements(address, NULL);
184 if (!addr) {
185 log::error("Bluetooth device address null");
186 return JNI_FALSE;
187 }
188
189 jboolean ret = JNI_TRUE;
190 bt_status_t status = sPanIf->disconnect((RawAddress*)addr);
191 if (status != BT_STATUS_SUCCESS) {
192 log::error("Failed disconnect pan channel, status: {}",
193 bt_status_text(status));
194 ret = JNI_FALSE;
195 }
196 env->ReleaseByteArrayElements(address, addr, 0);
197
198 return ret;
199 }
200
register_com_android_bluetooth_pan(JNIEnv * env)201 int register_com_android_bluetooth_pan(JNIEnv* env) {
202 const JNINativeMethod methods[] = {
203 {"initializeNative", "()V", (void*)initializeNative},
204 {"cleanupNative", "()V", (void*)cleanupNative},
205 {"connectPanNative", "([BII)Z", (void*)connectPanNative},
206 {"disconnectPanNative", "([B)Z", (void*)disconnectPanNative},
207 };
208 const int result = REGISTER_NATIVE_METHODS(
209 env, "com/android/bluetooth/pan/PanNativeInterface", methods);
210 if (result != 0) {
211 return result;
212 }
213
214 const JNIJavaMethod javaMethods[]{
215 {"onConnectStateChanged", "([BIIII)V", &method_onConnectStateChanged},
216 {"onControlStateChanged", "(IIILjava/lang/String;)V",
217 &method_onControlStateChanged},
218 };
219 GET_JAVA_METHODS(env, "com/android/bluetooth/pan/PanNativeInterface",
220 javaMethods);
221
222 return 0;
223 }
224 }
225