blob: b0ba6955c3b6b739877c9a58f35f79f5aae01ae9 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2** Copyright 2008, 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 "BluetoothEventLoop.cpp"
18
19#include "android_bluetooth_common.h"
20#include "android_runtime/AndroidRuntime.h"
Robert Greenwalt28d139f2009-04-02 22:41:08 -070021#include "cutils/sockets.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022#include "JNIHelp.h"
23#include "jni.h"
24#include "utils/Log.h"
25#include "utils/misc.h"
26
27#include <stdio.h>
28#include <string.h>
29#include <stdlib.h>
30#include <errno.h>
31#include <unistd.h>
32
33#ifdef HAVE_BLUETOOTH
34#include <dbus/dbus.h>
35#endif
36
37namespace android {
38
Nick Pelly16fb88a2009-10-07 07:44:03 +020039#define CREATE_DEVICE_ALREADY_EXISTS 1
40#define CREATE_DEVICE_SUCCESS 0
41#define CREATE_DEVICE_FAILED -1
42
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043#ifdef HAVE_BLUETOOTH
44static jfieldID field_mNativeData;
45
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -070046static jmethodID method_onPropertyChanged;
47static jmethodID method_onDevicePropertyChanged;
48static jmethodID method_onDeviceFound;
49static jmethodID method_onDeviceDisappeared;
50static jmethodID method_onDeviceCreated;
51static jmethodID method_onDeviceRemoved;
Jaikumar Ganesh5e59ca82009-09-11 12:16:19 -070052static jmethodID method_onDeviceDisconnectRequested;
Jaikumar Ganeshc1520ec2010-08-31 19:55:10 -070053static jmethodID method_onNetworkDeviceDisconnected;
54static jmethodID method_onNetworkDeviceConnected;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -070056static jmethodID method_onCreatePairedDeviceResult;
Jaikumar Ganesh1caa6d12009-09-18 11:32:54 -070057static jmethodID method_onCreateDeviceResult;
58static jmethodID method_onDiscoverServicesResult;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -070059static jmethodID method_onGetDeviceServiceChannelResult;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -070061static jmethodID method_onRequestPinCode;
Jaikumar Ganeshb0eca412009-07-16 18:26:28 -070062static jmethodID method_onRequestPasskey;
Jaikumar Ganesh32d85712009-09-10 22:00:05 -070063static jmethodID method_onRequestPasskeyConfirmation;
64static jmethodID method_onRequestPairingConsent;
65static jmethodID method_onDisplayPasskey;
Jaikumar Ganeshcc5494c2010-09-09 15:37:57 -070066static jmethodID method_onRequestOobData;
67static jmethodID method_onAgentOutOfBandDataAvailable;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -070068static jmethodID method_onAgentAuthorize;
69static jmethodID method_onAgentCancel;
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -070070
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070071static jmethodID method_onInputDevicePropertyChanged;
Jaikumar Ganeshde075032010-07-19 16:28:27 -070072static jmethodID method_onInputDeviceConnectionResult;
Danica Chang6fdd0c62010-08-11 14:54:43 -070073static jmethodID method_onPanDevicePropertyChanged;
74static jmethodID method_onPanDeviceConnectionResult;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070075
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080076typedef event_loop_native_data_t native_data_t;
77
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -070078#define EVENT_LOOP_REFS 10
79
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080080static inline native_data_t * get_native_data(JNIEnv *env, jobject object) {
81 return (native_data_t *)(env->GetIntField(object,
82 field_mNativeData));
83}
84
Robert Greenwalt28d139f2009-04-02 22:41:08 -070085native_data_t *get_EventLoop_native_data(JNIEnv *env, jobject object) {
86 return get_native_data(env, object);
87}
88
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080089#endif
90static void classInitNative(JNIEnv* env, jclass clazz) {
91 LOGV(__FUNCTION__);
92
93#ifdef HAVE_BLUETOOTH
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -070094 method_onPropertyChanged = env->GetMethodID(clazz, "onPropertyChanged",
95 "([Ljava/lang/String;)V");
96 method_onDevicePropertyChanged = env->GetMethodID(clazz,
97 "onDevicePropertyChanged",
98 "(Ljava/lang/String;[Ljava/lang/String;)V");
99 method_onDeviceFound = env->GetMethodID(clazz, "onDeviceFound",
100 "(Ljava/lang/String;[Ljava/lang/String;)V");
101 method_onDeviceDisappeared = env->GetMethodID(clazz, "onDeviceDisappeared",
102 "(Ljava/lang/String;)V");
103 method_onDeviceCreated = env->GetMethodID(clazz, "onDeviceCreated", "(Ljava/lang/String;)V");
104 method_onDeviceRemoved = env->GetMethodID(clazz, "onDeviceRemoved", "(Ljava/lang/String;)V");
Jaikumar Ganesh5e59ca82009-09-11 12:16:19 -0700105 method_onDeviceDisconnectRequested = env->GetMethodID(clazz, "onDeviceDisconnectRequested",
106 "(Ljava/lang/String;)V");
Jaikumar Ganeshc1520ec2010-08-31 19:55:10 -0700107 method_onNetworkDeviceConnected = env->GetMethodID(clazz, "onNetworkDeviceConnected",
Jaikumar Ganesh707952e2010-09-13 19:04:54 -0700108 "(Ljava/lang/String;Ljava/lang/String;I)V");
Jaikumar Ganeshc1520ec2010-08-31 19:55:10 -0700109 method_onNetworkDeviceDisconnected = env->GetMethodID(clazz, "onNetworkDeviceDisconnected",
110 "(Ljava/lang/String;)V");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800111
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700112 method_onCreatePairedDeviceResult = env->GetMethodID(clazz, "onCreatePairedDeviceResult",
113 "(Ljava/lang/String;I)V");
Jaikumar Ganesh1caa6d12009-09-18 11:32:54 -0700114 method_onCreateDeviceResult = env->GetMethodID(clazz, "onCreateDeviceResult",
Nick Pelly16fb88a2009-10-07 07:44:03 +0200115 "(Ljava/lang/String;I)V");
Jaikumar Ganesh1caa6d12009-09-18 11:32:54 -0700116 method_onDiscoverServicesResult = env->GetMethodID(clazz, "onDiscoverServicesResult",
117 "(Ljava/lang/String;Z)V");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800118
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700119 method_onAgentAuthorize = env->GetMethodID(clazz, "onAgentAuthorize",
120 "(Ljava/lang/String;Ljava/lang/String;)Z");
Jaikumar Ganeshcc5494c2010-09-09 15:37:57 -0700121 method_onAgentOutOfBandDataAvailable = env->GetMethodID(clazz, "onAgentOutOfBandDataAvailable",
122 "(Ljava/lang/String;)Z");
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700123 method_onAgentCancel = env->GetMethodID(clazz, "onAgentCancel", "()V");
124 method_onRequestPinCode = env->GetMethodID(clazz, "onRequestPinCode",
125 "(Ljava/lang/String;I)V");
Jaikumar Ganeshb0eca412009-07-16 18:26:28 -0700126 method_onRequestPasskey = env->GetMethodID(clazz, "onRequestPasskey",
127 "(Ljava/lang/String;I)V");
Jaikumar Ganesh32d85712009-09-10 22:00:05 -0700128 method_onRequestPasskeyConfirmation = env->GetMethodID(clazz, "onRequestPasskeyConfirmation",
129 "(Ljava/lang/String;II)V");
130 method_onRequestPairingConsent = env->GetMethodID(clazz, "onRequestPairingConsent",
131 "(Ljava/lang/String;I)V");
132 method_onDisplayPasskey = env->GetMethodID(clazz, "onDisplayPasskey",
Jaikumar Ganeshb0eca412009-07-16 18:26:28 -0700133 "(Ljava/lang/String;II)V");
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700134 method_onInputDevicePropertyChanged = env->GetMethodID(clazz, "onInputDevicePropertyChanged",
Danica Chang6fdd0c62010-08-11 14:54:43 -0700135 "(Ljava/lang/String;[Ljava/lang/String;)V");
Jaikumar Ganeshde075032010-07-19 16:28:27 -0700136 method_onInputDeviceConnectionResult = env->GetMethodID(clazz, "onInputDeviceConnectionResult",
Danica Chang6fdd0c62010-08-11 14:54:43 -0700137 "(Ljava/lang/String;Z)V");
138 method_onPanDevicePropertyChanged = env->GetMethodID(clazz, "onPanDevicePropertyChanged",
139 "(Ljava/lang/String;[Ljava/lang/String;)V");
140 method_onPanDeviceConnectionResult = env->GetMethodID(clazz, "onPanDeviceConnectionResult",
141 "(Ljava/lang/String;Z)V");
Jaikumar Ganeshcc5494c2010-09-09 15:37:57 -0700142 method_onRequestOobData = env->GetMethodID(clazz, "onRequestOobData",
143 "(Ljava/lang/String;I)V");
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700144
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800145 field_mNativeData = env->GetFieldID(clazz, "mNativeData", "I");
146#endif
147}
148
149static void initializeNativeDataNative(JNIEnv* env, jobject object) {
150 LOGV(__FUNCTION__);
151#ifdef HAVE_BLUETOOTH
152 native_data_t *nat = (native_data_t *)calloc(1, sizeof(native_data_t));
153 if (NULL == nat) {
154 LOGE("%s: out of memory!", __FUNCTION__);
155 return;
156 }
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700157 memset(nat, 0, sizeof(native_data_t));
158
159 pthread_mutex_init(&(nat->thread_mutex), NULL);
160
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800161 env->SetIntField(object, field_mNativeData, (jint)nat);
162
163 {
164 DBusError err;
165 dbus_error_init(&err);
166 dbus_threads_init_default();
167 nat->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
168 if (dbus_error_is_set(&err)) {
169 LOGE("%s: Could not get onto the system bus!", __FUNCTION__);
170 dbus_error_free(&err);
171 }
Nick Pelly9e0a1952009-06-17 15:27:59 -0700172 dbus_connection_set_exit_on_disconnect(nat->conn, FALSE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800173 }
174#endif
175}
176
177static void cleanupNativeDataNative(JNIEnv* env, jobject object) {
178 LOGV(__FUNCTION__);
179#ifdef HAVE_BLUETOOTH
180 native_data_t *nat =
181 (native_data_t *)env->GetIntField(object, field_mNativeData);
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700182
183 pthread_mutex_destroy(&(nat->thread_mutex));
184
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800185 if (nat) {
186 free(nat);
187 }
188#endif
189}
190
191#ifdef HAVE_BLUETOOTH
192static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg,
193 void *data);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700194DBusHandlerResult agent_event_filter(DBusConnection *conn,
195 DBusMessage *msg,
196 void *data);
197static int register_agent(native_data_t *nat,
198 const char *agent_path, const char *capabilities);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800199
200static const DBusObjectPathVTable agent_vtable = {
201 NULL, agent_event_filter, NULL, NULL, NULL, NULL
202};
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800203
Nick Pelly4a364132009-06-18 15:05:34 -0700204static unsigned int unix_events_to_dbus_flags(short events) {
205 return (events & DBUS_WATCH_READABLE ? POLLIN : 0) |
206 (events & DBUS_WATCH_WRITABLE ? POLLOUT : 0) |
207 (events & DBUS_WATCH_ERROR ? POLLERR : 0) |
208 (events & DBUS_WATCH_HANGUP ? POLLHUP : 0);
209}
210
211static short dbus_flags_to_unix_events(unsigned int flags) {
212 return (flags & POLLIN ? DBUS_WATCH_READABLE : 0) |
213 (flags & POLLOUT ? DBUS_WATCH_WRITABLE : 0) |
214 (flags & POLLERR ? DBUS_WATCH_ERROR : 0) |
215 (flags & POLLHUP ? DBUS_WATCH_HANGUP : 0);
216}
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700217
218static jboolean setUpEventLoop(native_data_t *nat) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800219 LOGV(__FUNCTION__);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800220
221 if (nat != NULL && nat->conn != NULL) {
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700222 dbus_threads_init_default();
223 DBusError err;
224 dbus_error_init(&err);
225
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800226 // Add a filter for all incoming messages
227 if (!dbus_connection_add_filter(nat->conn, event_filter, nat, NULL)){
228 return JNI_FALSE;
229 }
230
231 // Set which messages will be processed by this dbus connection
232 dbus_bus_add_match(nat->conn,
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700233 "type='signal',interface='org.freedesktop.DBus'",
234 &err);
235 if (dbus_error_is_set(&err)) {
236 LOG_AND_FREE_DBUS_ERROR(&err);
237 return JNI_FALSE;
238 }
239 dbus_bus_add_match(nat->conn,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800240 "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".Adapter'",
241 &err);
242 if (dbus_error_is_set(&err)) {
243 LOG_AND_FREE_DBUS_ERROR(&err);
244 return JNI_FALSE;
245 }
246 dbus_bus_add_match(nat->conn,
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700247 "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".Device'",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800248 &err);
249 if (dbus_error_is_set(&err)) {
250 LOG_AND_FREE_DBUS_ERROR(&err);
251 return JNI_FALSE;
252 }
253 dbus_bus_add_match(nat->conn,
Jaikumar Ganesh56d26132010-07-15 15:56:04 -0700254 "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".Input'",
255 &err);
256 if (dbus_error_is_set(&err)) {
257 LOG_AND_FREE_DBUS_ERROR(&err);
258 return JNI_FALSE;
259 }
260 dbus_bus_add_match(nat->conn,
261 "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".Network'",
262 &err);
263 if (dbus_error_is_set(&err)) {
264 LOG_AND_FREE_DBUS_ERROR(&err);
265 return JNI_FALSE;
266 }
267 dbus_bus_add_match(nat->conn,
Jaikumar Ganeshc1520ec2010-08-31 19:55:10 -0700268 "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".NetworkServer'",
269 &err);
270 if (dbus_error_is_set(&err)) {
271 LOG_AND_FREE_DBUS_ERROR(&err);
272 return JNI_FALSE;
273 }
274 dbus_bus_add_match(nat->conn,
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700275 "type='signal',interface='org.bluez.AudioSink'",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800276 &err);
277 if (dbus_error_is_set(&err)) {
278 LOG_AND_FREE_DBUS_ERROR(&err);
279 return JNI_FALSE;
280 }
281
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700282 const char *agent_path = "/android/bluetooth/agent";
283 const char *capabilities = "DisplayYesNo";
284 if (register_agent(nat, agent_path, capabilities) < 0) {
285 dbus_connection_unregister_object_path (nat->conn, agent_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800286 return JNI_FALSE;
287 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800288 return JNI_TRUE;
289 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800290 return JNI_FALSE;
291}
292
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700293
294const char * get_adapter_path(DBusConnection *conn) {
Jaikumar Ganesh32d85712009-09-10 22:00:05 -0700295 DBusMessage *msg = NULL, *reply = NULL;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700296 DBusError err;
297 const char *device_path = NULL;
Jaikumar Ganesh176c3d62009-09-01 09:56:56 -0700298 int attempt = 0;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700299
Jaikumar Ganesh176c3d62009-09-01 09:56:56 -0700300 for (attempt = 0; attempt < 1000 && reply == NULL; attempt ++) {
301 msg = dbus_message_new_method_call("org.bluez", "/",
302 "org.bluez.Manager", "DefaultAdapter");
303 if (!msg) {
304 LOGE("%s: Can't allocate new method call for get_adapter_path!",
305 __FUNCTION__);
306 return NULL;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700307 }
Jaikumar Ganesh176c3d62009-09-01 09:56:56 -0700308 dbus_message_append_args(msg, DBUS_TYPE_INVALID);
309 dbus_error_init(&err);
310 reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
311
312 if (!reply) {
313 if (dbus_error_is_set(&err)) {
314 if (dbus_error_has_name(&err,
315 "org.freedesktop.DBus.Error.ServiceUnknown")) {
316 // bluetoothd is still down, retry
317 LOG_AND_FREE_DBUS_ERROR(&err);
318 usleep(10000); // 10 ms
319 continue;
320 } else {
321 // Some other error we weren't expecting
322 LOG_AND_FREE_DBUS_ERROR(&err);
323 }
324 }
325 goto failed;
326 }
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700327 }
Jaikumar Ganesh176c3d62009-09-01 09:56:56 -0700328 if (attempt == 1000) {
329 LOGE("Time out while trying to get Adapter path, is bluetoothd up ?");
330 goto failed;
331 }
332
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700333 if (!dbus_message_get_args(reply, &err, DBUS_TYPE_OBJECT_PATH,
334 &device_path, DBUS_TYPE_INVALID)
335 || !device_path){
336 if (dbus_error_is_set(&err)) {
337 LOG_AND_FREE_DBUS_ERROR(&err);
338 }
Jaikumar Ganesh176c3d62009-09-01 09:56:56 -0700339 goto failed;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700340 }
Jaikumar Ganesh176c3d62009-09-01 09:56:56 -0700341 dbus_message_unref(msg);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700342 return device_path;
Jaikumar Ganesh176c3d62009-09-01 09:56:56 -0700343
344failed:
345 dbus_message_unref(msg);
346 return NULL;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700347}
348
349static int register_agent(native_data_t *nat,
350 const char * agent_path, const char * capabilities)
351{
352 DBusMessage *msg, *reply;
353 DBusError err;
Jaikumar Ganeshcc5494c2010-09-09 15:37:57 -0700354 bool oob = TRUE;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700355
356 if (!dbus_connection_register_object_path(nat->conn, agent_path,
357 &agent_vtable, nat)) {
358 LOGE("%s: Can't register object path %s for agent!",
359 __FUNCTION__, agent_path);
360 return -1;
361 }
362
363 nat->adapter = get_adapter_path(nat->conn);
Jaikumar Ganesh176c3d62009-09-01 09:56:56 -0700364 if (nat->adapter == NULL) {
365 return -1;
366 }
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700367 msg = dbus_message_new_method_call("org.bluez", nat->adapter,
368 "org.bluez.Adapter", "RegisterAgent");
369 if (!msg) {
370 LOGE("%s: Can't allocate new method call for agent!",
371 __FUNCTION__);
372 return -1;
373 }
374 dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &agent_path,
375 DBUS_TYPE_STRING, &capabilities,
Jaikumar Ganeshcc5494c2010-09-09 15:37:57 -0700376 DBUS_TYPE_BOOLEAN, &oob,
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700377 DBUS_TYPE_INVALID);
378
379 dbus_error_init(&err);
380 reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err);
381 dbus_message_unref(msg);
382
383 if (!reply) {
384 LOGE("%s: Can't register agent!", __FUNCTION__);
385 if (dbus_error_is_set(&err)) {
386 LOG_AND_FREE_DBUS_ERROR(&err);
387 }
388 return -1;
389 }
390
391 dbus_message_unref(reply);
392 dbus_connection_flush(nat->conn);
393
394 return 0;
395}
396
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700397static void tearDownEventLoop(native_data_t *nat) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800398 LOGV(__FUNCTION__);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800399 if (nat != NULL && nat->conn != NULL) {
400
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700401 DBusMessage *msg, *reply;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800402 DBusError err;
403 dbus_error_init(&err);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700404 const char * agent_path = "/android/bluetooth/agent";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800405
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700406 msg = dbus_message_new_method_call("org.bluez",
407 nat->adapter,
408 "org.bluez.Adapter",
409 "UnregisterAgent");
Jaikumar Ganesh9b0fe602009-06-11 15:10:45 -0700410 if (msg != NULL) {
411 dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &agent_path,
412 DBUS_TYPE_INVALID);
413 reply = dbus_connection_send_with_reply_and_block(nat->conn,
414 msg, -1, &err);
415
416 if (!reply) {
417 if (dbus_error_is_set(&err)) {
418 LOG_AND_FREE_DBUS_ERROR(&err);
419 dbus_error_free(&err);
420 }
421 } else {
422 dbus_message_unref(reply);
423 }
424 dbus_message_unref(msg);
425 } else {
426 LOGE("%s: Can't create new method call!", __FUNCTION__);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700427 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800428
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700429 dbus_connection_flush(nat->conn);
430 dbus_connection_unregister_object_path(nat->conn, agent_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800431
432 dbus_bus_remove_match(nat->conn,
Jaikumar Ganeshc1520ec2010-08-31 19:55:10 -0700433 "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".AudioSink'",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800434 &err);
435 if (dbus_error_is_set(&err)) {
436 LOG_AND_FREE_DBUS_ERROR(&err);
437 }
438 dbus_bus_remove_match(nat->conn,
Jaikumar Ganeshc1520ec2010-08-31 19:55:10 -0700439 "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".Device'",
440 &err);
441 if (dbus_error_is_set(&err)) {
442 LOG_AND_FREE_DBUS_ERROR(&err);
443 }
444 dbus_bus_remove_match(nat->conn,
445 "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".Input'",
446 &err);
447 if (dbus_error_is_set(&err)) {
448 LOG_AND_FREE_DBUS_ERROR(&err);
449 }
450 dbus_bus_remove_match(nat->conn,
451 "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".Network'",
452 &err);
453 if (dbus_error_is_set(&err)) {
454 LOG_AND_FREE_DBUS_ERROR(&err);
455 }
456 dbus_bus_remove_match(nat->conn,
457 "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".NetworkServer'",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800458 &err);
459 if (dbus_error_is_set(&err)) {
460 LOG_AND_FREE_DBUS_ERROR(&err);
461 }
462 dbus_bus_remove_match(nat->conn,
463 "type='signal',interface='org.bluez.audio.Manager'",
464 &err);
465 if (dbus_error_is_set(&err)) {
466 LOG_AND_FREE_DBUS_ERROR(&err);
467 }
468 dbus_bus_remove_match(nat->conn,
469 "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".Adapter'",
470 &err);
471 if (dbus_error_is_set(&err)) {
472 LOG_AND_FREE_DBUS_ERROR(&err);
473 }
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700474 dbus_bus_remove_match(nat->conn,
475 "type='signal',interface='org.freedesktop.DBus'",
476 &err);
477 if (dbus_error_is_set(&err)) {
478 LOG_AND_FREE_DBUS_ERROR(&err);
479 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800480
481 dbus_connection_remove_filter(nat->conn, event_filter, nat);
482 }
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700483}
484
485
486#define EVENT_LOOP_EXIT 1
487#define EVENT_LOOP_ADD 2
488#define EVENT_LOOP_REMOVE 3
489
490dbus_bool_t dbusAddWatch(DBusWatch *watch, void *data) {
491 native_data_t *nat = (native_data_t *)data;
492
493 if (dbus_watch_get_enabled(watch)) {
494 // note that we can't just send the watch and inspect it later
495 // because we may get a removeWatch call before this data is reacted
496 // to by our eventloop and remove this watch.. reading the add first
497 // and then inspecting the recently deceased watch would be bad.
498 char control = EVENT_LOOP_ADD;
499 write(nat->controlFdW, &control, sizeof(char));
500
501 int fd = dbus_watch_get_fd(watch);
502 write(nat->controlFdW, &fd, sizeof(int));
503
504 unsigned int flags = dbus_watch_get_flags(watch);
505 write(nat->controlFdW, &flags, sizeof(unsigned int));
506
507 write(nat->controlFdW, &watch, sizeof(DBusWatch*));
508 }
509 return true;
510}
511
512void dbusRemoveWatch(DBusWatch *watch, void *data) {
513 native_data_t *nat = (native_data_t *)data;
514
515 char control = EVENT_LOOP_REMOVE;
516 write(nat->controlFdW, &control, sizeof(char));
517
518 int fd = dbus_watch_get_fd(watch);
519 write(nat->controlFdW, &fd, sizeof(int));
520
521 unsigned int flags = dbus_watch_get_flags(watch);
522 write(nat->controlFdW, &flags, sizeof(unsigned int));
523}
524
525void dbusToggleWatch(DBusWatch *watch, void *data) {
526 if (dbus_watch_get_enabled(watch)) {
527 dbusAddWatch(watch, data);
528 } else {
529 dbusRemoveWatch(watch, data);
530 }
531}
532
533static void handleWatchAdd(native_data_t *nat) {
534 DBusWatch *watch;
535 int newFD;
536 unsigned int flags;
537
538 read(nat->controlFdR, &newFD, sizeof(int));
539 read(nat->controlFdR, &flags, sizeof(unsigned int));
540 read(nat->controlFdR, &watch, sizeof(DBusWatch *));
Nick Pelly4a364132009-06-18 15:05:34 -0700541 short events = dbus_flags_to_unix_events(flags);
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700542
543 for (int y = 0; y<nat->pollMemberCount; y++) {
544 if ((nat->pollData[y].fd == newFD) &&
545 (nat->pollData[y].events == events)) {
546 LOGV("DBusWatch duplicate add");
547 return;
548 }
549 }
550 if (nat->pollMemberCount == nat->pollDataSize) {
551 LOGV("Bluetooth EventLoop poll struct growing");
552 struct pollfd *temp = (struct pollfd *)malloc(
553 sizeof(struct pollfd) * (nat->pollMemberCount+1));
554 if (!temp) {
555 return;
556 }
557 memcpy(temp, nat->pollData, sizeof(struct pollfd) *
558 nat->pollMemberCount);
559 free(nat->pollData);
560 nat->pollData = temp;
561 DBusWatch **temp2 = (DBusWatch **)malloc(sizeof(DBusWatch *) *
562 (nat->pollMemberCount+1));
563 if (!temp2) {
564 return;
565 }
566 memcpy(temp2, nat->watchData, sizeof(DBusWatch *) *
567 nat->pollMemberCount);
568 free(nat->watchData);
569 nat->watchData = temp2;
570 nat->pollDataSize++;
571 }
572 nat->pollData[nat->pollMemberCount].fd = newFD;
573 nat->pollData[nat->pollMemberCount].revents = 0;
574 nat->pollData[nat->pollMemberCount].events = events;
575 nat->watchData[nat->pollMemberCount] = watch;
576 nat->pollMemberCount++;
577}
578
579static void handleWatchRemove(native_data_t *nat) {
580 int removeFD;
581 unsigned int flags;
582
583 read(nat->controlFdR, &removeFD, sizeof(int));
584 read(nat->controlFdR, &flags, sizeof(unsigned int));
Nick Pelly4a364132009-06-18 15:05:34 -0700585 short events = dbus_flags_to_unix_events(flags);
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700586
587 for (int y = 0; y < nat->pollMemberCount; y++) {
588 if ((nat->pollData[y].fd == removeFD) &&
589 (nat->pollData[y].events == events)) {
590 int newCount = --nat->pollMemberCount;
591 // copy the last live member over this one
592 nat->pollData[y].fd = nat->pollData[newCount].fd;
593 nat->pollData[y].events = nat->pollData[newCount].events;
594 nat->pollData[y].revents = nat->pollData[newCount].revents;
595 nat->watchData[y] = nat->watchData[newCount];
596 return;
597 }
598 }
599 LOGW("WatchRemove given with unknown watch");
600}
601
602static void *eventLoopMain(void *ptr) {
603 native_data_t *nat = (native_data_t *)ptr;
604 JNIEnv *env;
605
606 JavaVMAttachArgs args;
607 char name[] = "BT EventLoop";
608 args.version = nat->envVer;
609 args.name = name;
610 args.group = NULL;
611
612 nat->vm->AttachCurrentThread(&env, &args);
613
614 dbus_connection_set_watch_functions(nat->conn, dbusAddWatch,
615 dbusRemoveWatch, dbusToggleWatch, ptr, NULL);
616
Jaikumar Ganeshb8aa0372010-03-31 11:23:49 -0700617 nat->running = true;
618
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700619 while (1) {
620 for (int i = 0; i < nat->pollMemberCount; i++) {
621 if (!nat->pollData[i].revents) {
622 continue;
623 }
624 if (nat->pollData[i].fd == nat->controlFdR) {
625 char data;
626 while (recv(nat->controlFdR, &data, sizeof(char), MSG_DONTWAIT)
627 != -1) {
628 switch (data) {
629 case EVENT_LOOP_EXIT:
630 {
631 dbus_connection_set_watch_functions(nat->conn,
632 NULL, NULL, NULL, NULL, NULL);
633 tearDownEventLoop(nat);
634 nat->vm->DetachCurrentThread();
Johannes Carlssoned0d1ab2010-03-08 10:19:31 +0100635
636 int fd = nat->controlFdR;
637 nat->controlFdR = 0;
638 close(fd);
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700639 return NULL;
640 }
641 case EVENT_LOOP_ADD:
642 {
643 handleWatchAdd(nat);
644 break;
645 }
646 case EVENT_LOOP_REMOVE:
647 {
648 handleWatchRemove(nat);
649 break;
650 }
651 }
652 }
653 } else {
Nick Pelly4a364132009-06-18 15:05:34 -0700654 short events = nat->pollData[i].revents;
655 unsigned int flags = unix_events_to_dbus_flags(events);
656 dbus_watch_handle(nat->watchData[i], flags);
657 nat->pollData[i].revents = 0;
658 // can only do one - it may have caused a 'remove'
659 break;
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700660 }
661 }
Jaikumar Ganeshb8aa0372010-03-31 11:23:49 -0700662 while (dbus_connection_dispatch(nat->conn) ==
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700663 DBUS_DISPATCH_DATA_REMAINS) {
664 }
665
666 poll(nat->pollData, nat->pollMemberCount, -1);
667 }
668}
669#endif // HAVE_BLUETOOTH
670
671static jboolean startEventLoopNative(JNIEnv *env, jobject object) {
672 jboolean result = JNI_FALSE;
673#ifdef HAVE_BLUETOOTH
674 event_loop_native_data_t *nat = get_native_data(env, object);
675
676 pthread_mutex_lock(&(nat->thread_mutex));
677
Jaikumar Ganeshb8aa0372010-03-31 11:23:49 -0700678 nat->running = false;
679
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700680 if (nat->pollData) {
681 LOGW("trying to start EventLoop a second time!");
682 pthread_mutex_unlock( &(nat->thread_mutex) );
683 return JNI_FALSE;
684 }
685
686 nat->pollData = (struct pollfd *)malloc(sizeof(struct pollfd) *
687 DEFAULT_INITIAL_POLLFD_COUNT);
688 if (!nat->pollData) {
689 LOGE("out of memory error starting EventLoop!");
690 goto done;
691 }
692
693 nat->watchData = (DBusWatch **)malloc(sizeof(DBusWatch *) *
694 DEFAULT_INITIAL_POLLFD_COUNT);
695 if (!nat->watchData) {
696 LOGE("out of memory error starting EventLoop!");
697 goto done;
698 }
699
700 memset(nat->pollData, 0, sizeof(struct pollfd) *
701 DEFAULT_INITIAL_POLLFD_COUNT);
702 memset(nat->watchData, 0, sizeof(DBusWatch *) *
703 DEFAULT_INITIAL_POLLFD_COUNT);
704 nat->pollDataSize = DEFAULT_INITIAL_POLLFD_COUNT;
705 nat->pollMemberCount = 1;
706
707 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, &(nat->controlFdR))) {
708 LOGE("Error getting BT control socket");
709 goto done;
710 }
711 nat->pollData[0].fd = nat->controlFdR;
712 nat->pollData[0].events = POLLIN;
713
714 env->GetJavaVM( &(nat->vm) );
715 nat->envVer = env->GetVersion();
716
717 nat->me = env->NewGlobalRef(object);
718
719 if (setUpEventLoop(nat) != JNI_TRUE) {
720 LOGE("failure setting up Event Loop!");
721 goto done;
722 }
723
724 pthread_create(&(nat->thread), NULL, eventLoopMain, nat);
725 result = JNI_TRUE;
726
727done:
728 if (JNI_FALSE == result) {
Johannes Carlssoned0d1ab2010-03-08 10:19:31 +0100729 if (nat->controlFdW) {
730 close(nat->controlFdW);
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700731 nat->controlFdW = 0;
Johannes Carlssoned0d1ab2010-03-08 10:19:31 +0100732 }
733 if (nat->controlFdR) {
734 close(nat->controlFdR);
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700735 nat->controlFdR = 0;
736 }
737 if (nat->me) env->DeleteGlobalRef(nat->me);
738 nat->me = NULL;
739 if (nat->pollData) free(nat->pollData);
740 nat->pollData = NULL;
741 if (nat->watchData) free(nat->watchData);
742 nat->watchData = NULL;
743 nat->pollDataSize = 0;
744 nat->pollMemberCount = 0;
745 }
746
747 pthread_mutex_unlock(&(nat->thread_mutex));
748#endif // HAVE_BLUETOOTH
749 return result;
750}
751
752static void stopEventLoopNative(JNIEnv *env, jobject object) {
753#ifdef HAVE_BLUETOOTH
754 native_data_t *nat = get_native_data(env, object);
755
756 pthread_mutex_lock(&(nat->thread_mutex));
757 if (nat->pollData) {
758 char data = EVENT_LOOP_EXIT;
759 ssize_t t = write(nat->controlFdW, &data, sizeof(char));
760 void *ret;
761 pthread_join(nat->thread, &ret);
762
763 env->DeleteGlobalRef(nat->me);
764 nat->me = NULL;
765 free(nat->pollData);
766 nat->pollData = NULL;
767 free(nat->watchData);
768 nat->watchData = NULL;
769 nat->pollDataSize = 0;
770 nat->pollMemberCount = 0;
Johannes Carlssoned0d1ab2010-03-08 10:19:31 +0100771
772 int fd = nat->controlFdW;
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700773 nat->controlFdW = 0;
Johannes Carlssoned0d1ab2010-03-08 10:19:31 +0100774 close(fd);
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700775 }
Jaikumar Ganeshb8aa0372010-03-31 11:23:49 -0700776 nat->running = false;
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700777 pthread_mutex_unlock(&(nat->thread_mutex));
778#endif // HAVE_BLUETOOTH
779}
780
781static jboolean isEventLoopRunningNative(JNIEnv *env, jobject object) {
782 jboolean result = JNI_FALSE;
783#ifdef HAVE_BLUETOOTH
784 native_data_t *nat = get_native_data(env, object);
785
786 pthread_mutex_lock(&(nat->thread_mutex));
Jaikumar Ganeshb8aa0372010-03-31 11:23:49 -0700787 if (nat->running) {
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700788 result = JNI_TRUE;
789 }
790 pthread_mutex_unlock(&(nat->thread_mutex));
791
792#endif // HAVE_BLUETOOTH
793 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800794}
795
796#ifdef HAVE_BLUETOOTH
797extern DBusHandlerResult a2dp_event_filter(DBusMessage *msg, JNIEnv *env);
798
799// Called by dbus during WaitForAndDispatchEventNative()
800static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg,
801 void *data) {
802 native_data_t *nat;
803 JNIEnv *env;
804 DBusError err;
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -0700805 DBusHandlerResult ret;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800806
807 dbus_error_init(&err);
808
809 nat = (native_data_t *)data;
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700810 nat->vm->GetEnv((void**)&env, nat->envVer);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800811 if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_SIGNAL) {
812 LOGV("%s: not interested (not a signal).", __FUNCTION__);
813 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
814 }
815
Jaikumar Ganeshb1ef2442010-10-26 00:14:04 -0700816 LOGV("%s: Received signal %s:%s from %s", __FUNCTION__,
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700817 dbus_message_get_interface(msg), dbus_message_get_member(msg),
818 dbus_message_get_path(msg));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800819
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -0700820 env->PushLocalFrame(EVENT_LOOP_REFS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800821 if (dbus_message_is_signal(msg,
822 "org.bluez.Adapter",
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700823 "DeviceFound")) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800824 char *c_address;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700825 DBusMessageIter iter;
826 jobjectArray str_array = NULL;
827 if (dbus_message_iter_init(msg, &iter)) {
828 dbus_message_iter_get_basic(&iter, &c_address);
829 if (dbus_message_iter_next(&iter))
830 str_array =
831 parse_remote_device_properties(env, &iter);
832 }
833 if (str_array != NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800834 env->CallVoidMethod(nat->me,
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700835 method_onDeviceFound,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800836 env->NewStringUTF(c_address),
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700837 str_array);
838 } else
839 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -0700840 goto success;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800841 } else if (dbus_message_is_signal(msg,
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700842 "org.bluez.Adapter",
843 "DeviceDisappeared")) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800844 char *c_address;
845 if (dbus_message_get_args(msg, &err,
846 DBUS_TYPE_STRING, &c_address,
847 DBUS_TYPE_INVALID)) {
848 LOGV("... address = %s", c_address);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700849 env->CallVoidMethod(nat->me, method_onDeviceDisappeared,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800850 env->NewStringUTF(c_address));
851 } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -0700852 goto success;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800853 } else if (dbus_message_is_signal(msg,
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700854 "org.bluez.Adapter",
855 "DeviceCreated")) {
856 char *c_object_path;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800857 if (dbus_message_get_args(msg, &err,
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700858 DBUS_TYPE_OBJECT_PATH, &c_object_path,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800859 DBUS_TYPE_INVALID)) {
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700860 LOGV("... address = %s", c_object_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800861 env->CallVoidMethod(nat->me,
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700862 method_onDeviceCreated,
863 env->NewStringUTF(c_object_path));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800864 } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -0700865 goto success;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800866 } else if (dbus_message_is_signal(msg,
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700867 "org.bluez.Adapter",
868 "DeviceRemoved")) {
869 char *c_object_path;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800870 if (dbus_message_get_args(msg, &err,
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700871 DBUS_TYPE_OBJECT_PATH, &c_object_path,
872 DBUS_TYPE_INVALID)) {
873 LOGV("... Object Path = %s", c_object_path);
874 env->CallVoidMethod(nat->me,
875 method_onDeviceRemoved,
876 env->NewStringUTF(c_object_path));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800877 } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -0700878 goto success;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700879 } else if (dbus_message_is_signal(msg,
880 "org.bluez.Adapter",
881 "PropertyChanged")) {
882 jobjectArray str_array = parse_adapter_property_change(env, msg);
883 if (str_array != NULL) {
884 /* Check if bluetoothd has (re)started, if so update the path. */
885 jstring property =(jstring) env->GetObjectArrayElement(str_array, 0);
886 const char *c_property = env->GetStringUTFChars(property, NULL);
887 if (!strncmp(c_property, "Powered", strlen("Powered"))) {
888 jstring value =
889 (jstring) env->GetObjectArrayElement(str_array, 1);
890 const char *c_value = env->GetStringUTFChars(value, NULL);
891 if (!strncmp(c_value, "true", strlen("true")))
892 nat->adapter = get_adapter_path(nat->conn);
893 env->ReleaseStringUTFChars(value, c_value);
894 }
895 env->ReleaseStringUTFChars(property, c_property);
896
897 env->CallVoidMethod(nat->me,
898 method_onPropertyChanged,
899 str_array);
900 } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -0700901 goto success;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700902 } else if (dbus_message_is_signal(msg,
903 "org.bluez.Device",
904 "PropertyChanged")) {
905 jobjectArray str_array = parse_remote_device_property_change(env, msg);
906 if (str_array != NULL) {
907 const char *remote_device_path = dbus_message_get_path(msg);
908 env->CallVoidMethod(nat->me,
909 method_onDevicePropertyChanged,
910 env->NewStringUTF(remote_device_path),
911 str_array);
912 } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -0700913 goto success;
Jaikumar Ganesh5e59ca82009-09-11 12:16:19 -0700914 } else if (dbus_message_is_signal(msg,
915 "org.bluez.Device",
916 "DisconnectRequested")) {
917 const char *remote_device_path = dbus_message_get_path(msg);
918 env->CallVoidMethod(nat->me,
919 method_onDeviceDisconnectRequested,
920 env->NewStringUTF(remote_device_path));
921 goto success;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700922 } else if (dbus_message_is_signal(msg,
923 "org.bluez.Input",
924 "PropertyChanged")) {
925
926 jobjectArray str_array =
927 parse_input_property_change(env, msg);
928 if (str_array != NULL) {
929 const char *c_path = dbus_message_get_path(msg);
930 env->CallVoidMethod(nat->me,
931 method_onInputDevicePropertyChanged,
932 env->NewStringUTF(c_path),
933 str_array);
934 } else {
935 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
936 }
937 goto success;
Danica Chang6fdd0c62010-08-11 14:54:43 -0700938 } else if (dbus_message_is_signal(msg,
939 "org.bluez.Network",
940 "PropertyChanged")) {
941
942 jobjectArray str_array =
943 parse_pan_property_change(env, msg);
944 if (str_array != NULL) {
945 const char *c_path = dbus_message_get_path(msg);
946 env->CallVoidMethod(nat->me,
947 method_onPanDevicePropertyChanged,
948 env->NewStringUTF(c_path),
949 str_array);
950 } else {
951 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
952 }
953 goto success;
Jaikumar Ganeshc1520ec2010-08-31 19:55:10 -0700954 } else if (dbus_message_is_signal(msg,
955 "org.bluez.NetworkServer",
956 "DeviceDisconnected")) {
957 char *c_address;
958 if (dbus_message_get_args(msg, &err,
959 DBUS_TYPE_STRING, &c_address,
960 DBUS_TYPE_INVALID)) {
961 env->CallVoidMethod(nat->me,
962 method_onNetworkDeviceDisconnected,
963 env->NewStringUTF(c_address));
964 } else {
965 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
966 }
967 goto success;
968 } else if (dbus_message_is_signal(msg,
969 "org.bluez.NetworkServer",
970 "DeviceConnected")) {
971 char *c_address;
Jaikumar Ganesh707952e2010-09-13 19:04:54 -0700972 char *c_iface;
Jaikumar Ganeshc1520ec2010-08-31 19:55:10 -0700973 uint16_t uuid;
974
975 if (dbus_message_get_args(msg, &err,
976 DBUS_TYPE_STRING, &c_address,
Jaikumar Ganesh707952e2010-09-13 19:04:54 -0700977 DBUS_TYPE_STRING, &c_iface,
Jaikumar Ganeshc1520ec2010-08-31 19:55:10 -0700978 DBUS_TYPE_UINT16, &uuid,
979 DBUS_TYPE_INVALID)) {
980 env->CallVoidMethod(nat->me,
981 method_onNetworkDeviceConnected,
982 env->NewStringUTF(c_address),
Jaikumar Ganesh707952e2010-09-13 19:04:54 -0700983 env->NewStringUTF(c_iface),
Jaikumar Ganeshc1520ec2010-08-31 19:55:10 -0700984 uuid);
985 } else {
986 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
987 }
988 goto success;
989 }
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -0700990
991 ret = a2dp_event_filter(msg, env);
992 env->PopLocalFrame(NULL);
993 return ret;
994
995success:
996 env->PopLocalFrame(NULL);
997 return DBUS_HANDLER_RESULT_HANDLED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800998}
999
1000// Called by dbus during WaitForAndDispatchEventNative()
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -07001001DBusHandlerResult agent_event_filter(DBusConnection *conn,
1002 DBusMessage *msg, void *data) {
Robert Greenwalt28d139f2009-04-02 22:41:08 -07001003 native_data_t *nat = (native_data_t *)data;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001004 JNIEnv *env;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001005 if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_METHOD_CALL) {
1006 LOGV("%s: not interested (not a method call).", __FUNCTION__);
1007 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1008 }
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -07001009 LOGI("%s: Received method %s:%s", __FUNCTION__,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001010 dbus_message_get_interface(msg), dbus_message_get_member(msg));
1011
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -07001012 if (nat == NULL) return DBUS_HANDLER_RESULT_HANDLED;
1013
1014 nat->vm->GetEnv((void**)&env, nat->envVer);
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -07001015 env->PushLocalFrame(EVENT_LOOP_REFS);
1016
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001017 if (dbus_message_is_method_call(msg,
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -07001018 "org.bluez.Agent", "Cancel")) {
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -07001019 env->CallVoidMethod(nat->me, method_onAgentCancel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001020 // reply
1021 DBusMessage *reply = dbus_message_new_method_return(msg);
1022 if (!reply) {
1023 LOGE("%s: Cannot create message reply\n", __FUNCTION__);
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -07001024 goto failure;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001025 }
1026 dbus_connection_send(nat->conn, reply, NULL);
1027 dbus_message_unref(reply);
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -07001028 goto success;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001029
1030 } else if (dbus_message_is_method_call(msg,
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -07001031 "org.bluez.Agent", "Authorize")) {
1032 char *object_path;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001033 const char *uuid;
1034 if (!dbus_message_get_args(msg, NULL,
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -07001035 DBUS_TYPE_OBJECT_PATH, &object_path,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001036 DBUS_TYPE_STRING, &uuid,
1037 DBUS_TYPE_INVALID)) {
1038 LOGE("%s: Invalid arguments for Authorize() method", __FUNCTION__);
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -07001039 goto failure;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001040 }
1041
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -07001042 LOGV("... object_path = %s", object_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001043 LOGV("... uuid = %s", uuid);
1044
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -07001045 bool auth_granted =
1046 env->CallBooleanMethod(nat->me, method_onAgentAuthorize,
1047 env->NewStringUTF(object_path), env->NewStringUTF(uuid));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001048
1049 // reply
1050 if (auth_granted) {
1051 DBusMessage *reply = dbus_message_new_method_return(msg);
1052 if (!reply) {
1053 LOGE("%s: Cannot create message reply\n", __FUNCTION__);
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -07001054 goto failure;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001055 }
1056 dbus_connection_send(nat->conn, reply, NULL);
1057 dbus_message_unref(reply);
1058 } else {
1059 DBusMessage *reply = dbus_message_new_error(msg,
1060 "org.bluez.Error.Rejected", "Authorization rejected");
1061 if (!reply) {
1062 LOGE("%s: Cannot create message reply\n", __FUNCTION__);
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -07001063 goto failure;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001064 }
1065 dbus_connection_send(nat->conn, reply, NULL);
1066 dbus_message_unref(reply);
1067 }
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -07001068 goto success;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001069 } else if (dbus_message_is_method_call(msg,
Jaikumar Ganeshcc5494c2010-09-09 15:37:57 -07001070 "org.bluez.Agent", "OutOfBandAvailable")) {
1071 char *object_path;
1072 if (!dbus_message_get_args(msg, NULL,
1073 DBUS_TYPE_OBJECT_PATH, &object_path,
1074 DBUS_TYPE_INVALID)) {
1075 LOGE("%s: Invalid arguments for OutOfBandData available() method", __FUNCTION__);
1076 goto failure;
1077 }
1078
1079 LOGV("... object_path = %s", object_path);
1080
1081 bool available =
1082 env->CallBooleanMethod(nat->me, method_onAgentOutOfBandDataAvailable,
1083 env->NewStringUTF(object_path));
1084
1085
1086 // reply
1087 if (available) {
1088 DBusMessage *reply = dbus_message_new_method_return(msg);
1089 if (!reply) {
1090 LOGE("%s: Cannot create message reply\n", __FUNCTION__);
1091 goto failure;
1092 }
1093 dbus_connection_send(nat->conn, reply, NULL);
1094 dbus_message_unref(reply);
1095 } else {
1096 DBusMessage *reply = dbus_message_new_error(msg,
1097 "org.bluez.Error.DoesNotExist", "OutofBand data not available");
1098 if (!reply) {
1099 LOGE("%s: Cannot create message reply\n", __FUNCTION__);
1100 goto failure;
1101 }
1102 dbus_connection_send(nat->conn, reply, NULL);
1103 dbus_message_unref(reply);
1104 }
1105 goto success;
1106 } else if (dbus_message_is_method_call(msg,
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -07001107 "org.bluez.Agent", "RequestPinCode")) {
1108 char *object_path;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001109 if (!dbus_message_get_args(msg, NULL,
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -07001110 DBUS_TYPE_OBJECT_PATH, &object_path,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001111 DBUS_TYPE_INVALID)) {
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -07001112 LOGE("%s: Invalid arguments for RequestPinCode() method", __FUNCTION__);
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -07001113 goto failure;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001114 }
1115
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -07001116 dbus_message_ref(msg); // increment refcount because we pass to java
1117 env->CallVoidMethod(nat->me, method_onRequestPinCode,
1118 env->NewStringUTF(object_path),
1119 int(msg));
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -07001120 goto success;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001121 } else if (dbus_message_is_method_call(msg,
Jaikumar Ganeshb0eca412009-07-16 18:26:28 -07001122 "org.bluez.Agent", "RequestPasskey")) {
1123 char *object_path;
1124 if (!dbus_message_get_args(msg, NULL,
1125 DBUS_TYPE_OBJECT_PATH, &object_path,
1126 DBUS_TYPE_INVALID)) {
1127 LOGE("%s: Invalid arguments for RequestPasskey() method", __FUNCTION__);
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -07001128 goto failure;
Jaikumar Ganeshb0eca412009-07-16 18:26:28 -07001129 }
1130
1131 dbus_message_ref(msg); // increment refcount because we pass to java
1132 env->CallVoidMethod(nat->me, method_onRequestPasskey,
1133 env->NewStringUTF(object_path),
1134 int(msg));
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -07001135 goto success;
Jaikumar Ganeshb0eca412009-07-16 18:26:28 -07001136 } else if (dbus_message_is_method_call(msg,
Jaikumar Ganeshcc5494c2010-09-09 15:37:57 -07001137 "org.bluez.Agent", "RequestOobData")) {
1138 char *object_path;
1139 if (!dbus_message_get_args(msg, NULL,
1140 DBUS_TYPE_OBJECT_PATH, &object_path,
1141 DBUS_TYPE_INVALID)) {
1142 LOGE("%s: Invalid arguments for RequestOobData() method", __FUNCTION__);
1143 goto failure;
1144 }
1145
1146 dbus_message_ref(msg); // increment refcount because we pass to java
1147 env->CallVoidMethod(nat->me, method_onRequestOobData,
1148 env->NewStringUTF(object_path),
1149 int(msg));
1150 goto success;
1151 } else if (dbus_message_is_method_call(msg,
Jaikumar Ganesh32d85712009-09-10 22:00:05 -07001152 "org.bluez.Agent", "DisplayPasskey")) {
1153 char *object_path;
1154 uint32_t passkey;
1155 if (!dbus_message_get_args(msg, NULL,
1156 DBUS_TYPE_OBJECT_PATH, &object_path,
1157 DBUS_TYPE_UINT32, &passkey,
1158 DBUS_TYPE_INVALID)) {
1159 LOGE("%s: Invalid arguments for RequestPasskey() method", __FUNCTION__);
1160 goto failure;
1161 }
1162
1163 dbus_message_ref(msg); // increment refcount because we pass to java
1164 env->CallVoidMethod(nat->me, method_onDisplayPasskey,
1165 env->NewStringUTF(object_path),
1166 passkey,
1167 int(msg));
1168 goto success;
1169 } else if (dbus_message_is_method_call(msg,
Jaikumar Ganeshb0eca412009-07-16 18:26:28 -07001170 "org.bluez.Agent", "RequestConfirmation")) {
1171 char *object_path;
1172 uint32_t passkey;
1173 if (!dbus_message_get_args(msg, NULL,
1174 DBUS_TYPE_OBJECT_PATH, &object_path,
1175 DBUS_TYPE_UINT32, &passkey,
1176 DBUS_TYPE_INVALID)) {
1177 LOGE("%s: Invalid arguments for RequestConfirmation() method", __FUNCTION__);
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -07001178 goto failure;
Jaikumar Ganeshb0eca412009-07-16 18:26:28 -07001179 }
1180
1181 dbus_message_ref(msg); // increment refcount because we pass to java
Jaikumar Ganesh32d85712009-09-10 22:00:05 -07001182 env->CallVoidMethod(nat->me, method_onRequestPasskeyConfirmation,
Jaikumar Ganeshb0eca412009-07-16 18:26:28 -07001183 env->NewStringUTF(object_path),
1184 passkey,
1185 int(msg));
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -07001186 goto success;
Jaikumar Ganeshb0eca412009-07-16 18:26:28 -07001187 } else if (dbus_message_is_method_call(msg,
Jaikumar Ganesh32d85712009-09-10 22:00:05 -07001188 "org.bluez.Agent", "RequestPairingConsent")) {
1189 char *object_path;
1190 if (!dbus_message_get_args(msg, NULL,
1191 DBUS_TYPE_OBJECT_PATH, &object_path,
1192 DBUS_TYPE_INVALID)) {
1193 LOGE("%s: Invalid arguments for RequestPairingConsent() method", __FUNCTION__);
1194 goto failure;
1195 }
1196
1197 dbus_message_ref(msg); // increment refcount because we pass to java
1198 env->CallVoidMethod(nat->me, method_onRequestPairingConsent,
1199 env->NewStringUTF(object_path),
1200 int(msg));
1201 goto success;
1202 } else if (dbus_message_is_method_call(msg,
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -07001203 "org.bluez.Agent", "Release")) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001204 // reply
1205 DBusMessage *reply = dbus_message_new_method_return(msg);
1206 if (!reply) {
1207 LOGE("%s: Cannot create message reply\n", __FUNCTION__);
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -07001208 goto failure;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001209 }
1210 dbus_connection_send(nat->conn, reply, NULL);
1211 dbus_message_unref(reply);
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -07001212 goto success;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001213 } else {
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -07001214 LOGV("%s:%s is ignored", dbus_message_get_interface(msg), dbus_message_get_member(msg));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001215 }
1216
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -07001217failure:
1218 env->PopLocalFrame(NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001219 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -07001220
1221success:
1222 env->PopLocalFrame(NULL);
1223 return DBUS_HANDLER_RESULT_HANDLED;
1224
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001225}
1226#endif
1227
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001228
1229#ifdef HAVE_BLUETOOTH
1230//TODO: Unify result codes in a header
1231#define BOND_RESULT_ERROR -1000
1232#define BOND_RESULT_SUCCESS 0
1233#define BOND_RESULT_AUTH_FAILED 1
1234#define BOND_RESULT_AUTH_REJECTED 2
1235#define BOND_RESULT_AUTH_CANCELED 3
1236#define BOND_RESULT_REMOTE_DEVICE_DOWN 4
1237#define BOND_RESULT_DISCOVERY_IN_PROGRESS 5
Jaikumar Ganesh32d85712009-09-10 22:00:05 -07001238#define BOND_RESULT_AUTH_TIMEOUT 6
1239#define BOND_RESULT_REPEATED_ATTEMPTS 7
Robert Greenwalt28d139f2009-04-02 22:41:08 -07001240
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -07001241void onCreatePairedDeviceResult(DBusMessage *msg, void *user, void *n) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001242 LOGV(__FUNCTION__);
1243
Robert Greenwalt28d139f2009-04-02 22:41:08 -07001244 native_data_t *nat = (native_data_t *)n;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001245 const char *address = (const char *)user;
1246 DBusError err;
1247 dbus_error_init(&err);
Robert Greenwalt28d139f2009-04-02 22:41:08 -07001248 JNIEnv *env;
Jaikumar Ganesha7c0bdc2010-06-03 16:50:57 -07001249 jstring addr;
1250
Robert Greenwalt28d139f2009-04-02 22:41:08 -07001251 nat->vm->GetEnv((void**)&env, nat->envVer);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001252
1253 LOGV("... address = %s", address);
1254
1255 jint result = BOND_RESULT_SUCCESS;
1256 if (dbus_set_error_from_message(&err, msg)) {
1257 if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationFailed")) {
1258 // Pins did not match, or remote device did not respond to pin
1259 // request in time
1260 LOGV("... error = %s (%s)\n", err.name, err.message);
1261 result = BOND_RESULT_AUTH_FAILED;
1262 } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationRejected")) {
1263 // We rejected pairing, or the remote side rejected pairing. This
1264 // happens if either side presses 'cancel' at the pairing dialog.
1265 LOGV("... error = %s (%s)\n", err.name, err.message);
1266 result = BOND_RESULT_AUTH_REJECTED;
1267 } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationCanceled")) {
1268 // Not sure if this happens
1269 LOGV("... error = %s (%s)\n", err.name, err.message);
1270 result = BOND_RESULT_AUTH_CANCELED;
1271 } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.ConnectionAttemptFailed")) {
1272 // Other device is not responding at all
1273 LOGV("... error = %s (%s)\n", err.name, err.message);
1274 result = BOND_RESULT_REMOTE_DEVICE_DOWN;
1275 } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AlreadyExists")) {
1276 // already bonded
1277 LOGV("... error = %s (%s)\n", err.name, err.message);
1278 result = BOND_RESULT_SUCCESS;
1279 } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.InProgress") &&
1280 !strcmp(err.message, "Bonding in progress")) {
1281 LOGV("... error = %s (%s)\n", err.name, err.message);
1282 goto done;
1283 } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.InProgress") &&
1284 !strcmp(err.message, "Discover in progress")) {
1285 LOGV("... error = %s (%s)\n", err.name, err.message);
1286 result = BOND_RESULT_DISCOVERY_IN_PROGRESS;
Jaikumar Ganesh32d85712009-09-10 22:00:05 -07001287 } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.RepeatedAttempts")) {
1288 LOGV("... error = %s (%s)\n", err.name, err.message);
1289 result = BOND_RESULT_REPEATED_ATTEMPTS;
1290 } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationTimeout")) {
1291 LOGV("... error = %s (%s)\n", err.name, err.message);
1292 result = BOND_RESULT_AUTH_TIMEOUT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001293 } else {
1294 LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message);
1295 result = BOND_RESULT_ERROR;
1296 }
1297 }
1298
Jaikumar Ganesha7c0bdc2010-06-03 16:50:57 -07001299 addr = env->NewStringUTF(address);
Robert Greenwalt28d139f2009-04-02 22:41:08 -07001300 env->CallVoidMethod(nat->me,
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -07001301 method_onCreatePairedDeviceResult,
Jaikumar Ganesha7c0bdc2010-06-03 16:50:57 -07001302 addr,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001303 result);
Jaikumar Ganesha7c0bdc2010-06-03 16:50:57 -07001304 env->DeleteLocalRef(addr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001305done:
1306 dbus_error_free(&err);
1307 free(user);
1308}
1309
Jaikumar Ganesh1caa6d12009-09-18 11:32:54 -07001310void onCreateDeviceResult(DBusMessage *msg, void *user, void *n) {
1311 LOGV(__FUNCTION__);
1312
1313 native_data_t *nat = (native_data_t *)n;
1314 const char *address= (const char *)user;
1315 DBusError err;
1316 dbus_error_init(&err);
1317 JNIEnv *env;
1318 nat->vm->GetEnv((void**)&env, nat->envVer);
1319
1320 LOGV("... Address = %s", address);
1321
Nick Pelly16fb88a2009-10-07 07:44:03 +02001322 jint result = CREATE_DEVICE_SUCCESS;
Jaikumar Ganesh1caa6d12009-09-18 11:32:54 -07001323 if (dbus_set_error_from_message(&err, msg)) {
Nick Pelly16fb88a2009-10-07 07:44:03 +02001324 if (dbus_error_has_name(&err, "org.bluez.Error.AlreadyExists")) {
1325 result = CREATE_DEVICE_ALREADY_EXISTS;
Jaikumar Ganeshcf5f6522010-02-17 17:19:26 -08001326 } else {
1327 result = CREATE_DEVICE_FAILED;
Nick Pelly16fb88a2009-10-07 07:44:03 +02001328 }
Jaikumar Ganesh1caa6d12009-09-18 11:32:54 -07001329 LOG_AND_FREE_DBUS_ERROR(&err);
Jaikumar Ganesh1caa6d12009-09-18 11:32:54 -07001330 }
Jaikumar Ganesha7c0bdc2010-06-03 16:50:57 -07001331 jstring addr = env->NewStringUTF(address);
Jaikumar Ganesh1caa6d12009-09-18 11:32:54 -07001332 env->CallVoidMethod(nat->me,
1333 method_onCreateDeviceResult,
Jaikumar Ganesha7c0bdc2010-06-03 16:50:57 -07001334 addr,
Jaikumar Ganesh1caa6d12009-09-18 11:32:54 -07001335 result);
Jaikumar Ganesha7c0bdc2010-06-03 16:50:57 -07001336 env->DeleteLocalRef(addr);
Jaikumar Ganesh1caa6d12009-09-18 11:32:54 -07001337 free(user);
1338}
1339
1340void onDiscoverServicesResult(DBusMessage *msg, void *user, void *n) {
1341 LOGV(__FUNCTION__);
1342
1343 native_data_t *nat = (native_data_t *)n;
1344 const char *path = (const char *)user;
1345 DBusError err;
1346 dbus_error_init(&err);
1347 JNIEnv *env;
1348 nat->vm->GetEnv((void**)&env, nat->envVer);
1349
1350 LOGV("... Device Path = %s", path);
1351
1352 bool result = JNI_TRUE;
1353 if (dbus_set_error_from_message(&err, msg)) {
1354 LOG_AND_FREE_DBUS_ERROR(&err);
1355 result = JNI_FALSE;
1356 }
Jaikumar Ganesha7c0bdc2010-06-03 16:50:57 -07001357 jstring jPath = env->NewStringUTF(path);
Jaikumar Ganesh1caa6d12009-09-18 11:32:54 -07001358 env->CallVoidMethod(nat->me,
1359 method_onDiscoverServicesResult,
Jaikumar Ganesha7c0bdc2010-06-03 16:50:57 -07001360 jPath,
Jaikumar Ganesh1caa6d12009-09-18 11:32:54 -07001361 result);
Jaikumar Ganesha7c0bdc2010-06-03 16:50:57 -07001362 env->DeleteLocalRef(jPath);
Jaikumar Ganesh1caa6d12009-09-18 11:32:54 -07001363 free(user);
1364}
1365
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -07001366void onGetDeviceServiceChannelResult(DBusMessage *msg, void *user, void *n) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001367 LOGV(__FUNCTION__);
1368
1369 const char *address = (const char *) user;
Robert Greenwalt28d139f2009-04-02 22:41:08 -07001370 native_data_t *nat = (native_data_t *) n;
1371
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001372 DBusError err;
1373 dbus_error_init(&err);
Robert Greenwalt28d139f2009-04-02 22:41:08 -07001374 JNIEnv *env;
1375 nat->vm->GetEnv((void**)&env, nat->envVer);
1376
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001377 jint channel = -2;
1378
1379 LOGV("... address = %s", address);
1380
1381 if (dbus_set_error_from_message(&err, msg) ||
1382 !dbus_message_get_args(msg, &err,
1383 DBUS_TYPE_INT32, &channel,
1384 DBUS_TYPE_INVALID)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001385 LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message);
1386 dbus_error_free(&err);
1387 }
1388
1389done:
Jaikumar Ganesha7c0bdc2010-06-03 16:50:57 -07001390 jstring addr = env->NewStringUTF(address);
Robert Greenwalt28d139f2009-04-02 22:41:08 -07001391 env->CallVoidMethod(nat->me,
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -07001392 method_onGetDeviceServiceChannelResult,
Jaikumar Ganesha7c0bdc2010-06-03 16:50:57 -07001393 addr,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001394 channel);
Jaikumar Ganesha7c0bdc2010-06-03 16:50:57 -07001395 env->DeleteLocalRef(addr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001396 free(user);
1397}
Jaikumar Ganeshde075032010-07-19 16:28:27 -07001398
1399void onInputDeviceConnectionResult(DBusMessage *msg, void *user, void *n) {
1400 LOGV(__FUNCTION__);
1401
1402 native_data_t *nat = (native_data_t *)n;
1403 const char *path = (const char *)user;
1404 DBusError err;
1405 dbus_error_init(&err);
1406 JNIEnv *env;
1407 nat->vm->GetEnv((void**)&env, nat->envVer);
1408
1409 bool result = JNI_TRUE;
1410 if (dbus_set_error_from_message(&err, msg)) {
1411 LOG_AND_FREE_DBUS_ERROR(&err);
1412 result = JNI_FALSE;
1413 }
1414 LOGV("... Device Path = %s, result = %d", path, result);
1415 jstring jPath = env->NewStringUTF(path);
1416 env->CallVoidMethod(nat->me,
1417 method_onInputDeviceConnectionResult,
1418 jPath,
1419 result);
1420 env->DeleteLocalRef(jPath);
1421 free(user);
1422}
1423
Danica Chang6fdd0c62010-08-11 14:54:43 -07001424void onPanDeviceConnectionResult(DBusMessage *msg, void *user, void *n) {
1425 LOGV(__FUNCTION__);
1426
1427 native_data_t *nat = (native_data_t *)n;
1428 const char *path = (const char *)user;
1429 DBusError err;
1430 dbus_error_init(&err);
1431 JNIEnv *env;
1432 nat->vm->GetEnv((void**)&env, nat->envVer);
1433
1434 bool result = JNI_TRUE;
1435 if (dbus_set_error_from_message(&err, msg)) {
1436 LOG_AND_FREE_DBUS_ERROR(&err);
1437 result = JNI_FALSE;
1438 }
1439 LOGV("... Pan Device Path = %s, result = %d", path, result);
1440 jstring jPath = env->NewStringUTF(path);
1441 env->CallVoidMethod(nat->me,
1442 method_onPanDeviceConnectionResult,
1443 jPath,
1444 result);
1445 env->DeleteLocalRef(jPath);
1446 free(user);
1447}
1448
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001449#endif
1450
1451static JNINativeMethod sMethods[] = {
1452 /* name, signature, funcPtr */
1453 {"classInitNative", "()V", (void *)classInitNative},
1454 {"initializeNativeDataNative", "()V", (void *)initializeNativeDataNative},
1455 {"cleanupNativeDataNative", "()V", (void *)cleanupNativeDataNative},
Robert Greenwalt28d139f2009-04-02 22:41:08 -07001456 {"startEventLoopNative", "()V", (void *)startEventLoopNative},
1457 {"stopEventLoopNative", "()V", (void *)stopEventLoopNative},
1458 {"isEventLoopRunningNative", "()Z", (void *)isEventLoopRunningNative}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001459};
1460
1461int register_android_server_BluetoothEventLoop(JNIEnv *env) {
1462 return AndroidRuntime::registerNativeMethods(env,
1463 "android/server/BluetoothEventLoop", sMethods, NELEM(sMethods));
1464}
1465
1466} /* namespace android */