blob: 100fca4c62bff25f22329208f52179fc1a9cba35 [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 Ganesh2ea1e852011-04-01 16:33:09 -070075static jmethodID method_onHealthDevicePropertyChanged;
76static jmethodID method_onHealthDeviceChannelChanged;
Jaikumar Ganeshb5d2d452011-09-07 14:16:52 -070077static jmethodID method_onHealthDeviceConnectionResult;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070078
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079typedef event_loop_native_data_t native_data_t;
80
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -070081#define EVENT_LOOP_REFS 10
82
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083static inline native_data_t * get_native_data(JNIEnv *env, jobject object) {
84 return (native_data_t *)(env->GetIntField(object,
85 field_mNativeData));
86}
87
Robert Greenwalt28d139f2009-04-02 22:41:08 -070088native_data_t *get_EventLoop_native_data(JNIEnv *env, jobject object) {
89 return get_native_data(env, object);
90}
91
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092#endif
93static void classInitNative(JNIEnv* env, jclass clazz) {
Steve Block71f2cf12011-10-20 11:56:00 +010094 ALOGV("%s", __FUNCTION__);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095
96#ifdef HAVE_BLUETOOTH
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -070097 method_onPropertyChanged = env->GetMethodID(clazz, "onPropertyChanged",
98 "([Ljava/lang/String;)V");
99 method_onDevicePropertyChanged = env->GetMethodID(clazz,
100 "onDevicePropertyChanged",
101 "(Ljava/lang/String;[Ljava/lang/String;)V");
102 method_onDeviceFound = env->GetMethodID(clazz, "onDeviceFound",
103 "(Ljava/lang/String;[Ljava/lang/String;)V");
104 method_onDeviceDisappeared = env->GetMethodID(clazz, "onDeviceDisappeared",
105 "(Ljava/lang/String;)V");
106 method_onDeviceCreated = env->GetMethodID(clazz, "onDeviceCreated", "(Ljava/lang/String;)V");
107 method_onDeviceRemoved = env->GetMethodID(clazz, "onDeviceRemoved", "(Ljava/lang/String;)V");
Jaikumar Ganesh5e59ca82009-09-11 12:16:19 -0700108 method_onDeviceDisconnectRequested = env->GetMethodID(clazz, "onDeviceDisconnectRequested",
109 "(Ljava/lang/String;)V");
Jaikumar Ganeshc1520ec2010-08-31 19:55:10 -0700110 method_onNetworkDeviceConnected = env->GetMethodID(clazz, "onNetworkDeviceConnected",
Jaikumar Ganesh707952e2010-09-13 19:04:54 -0700111 "(Ljava/lang/String;Ljava/lang/String;I)V");
Jaikumar Ganeshc1520ec2010-08-31 19:55:10 -0700112 method_onNetworkDeviceDisconnected = env->GetMethodID(clazz, "onNetworkDeviceDisconnected",
113 "(Ljava/lang/String;)V");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800114
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700115 method_onCreatePairedDeviceResult = env->GetMethodID(clazz, "onCreatePairedDeviceResult",
116 "(Ljava/lang/String;I)V");
Jaikumar Ganesh1caa6d12009-09-18 11:32:54 -0700117 method_onCreateDeviceResult = env->GetMethodID(clazz, "onCreateDeviceResult",
Nick Pelly16fb88a2009-10-07 07:44:03 +0200118 "(Ljava/lang/String;I)V");
Jaikumar Ganesh1caa6d12009-09-18 11:32:54 -0700119 method_onDiscoverServicesResult = env->GetMethodID(clazz, "onDiscoverServicesResult",
120 "(Ljava/lang/String;Z)V");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800121
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700122 method_onAgentAuthorize = env->GetMethodID(clazz, "onAgentAuthorize",
Matthew Xiea0c68032011-06-25 21:47:07 -0700123 "(Ljava/lang/String;Ljava/lang/String;I)V");
Jaikumar Ganeshcc5494c2010-09-09 15:37:57 -0700124 method_onAgentOutOfBandDataAvailable = env->GetMethodID(clazz, "onAgentOutOfBandDataAvailable",
125 "(Ljava/lang/String;)Z");
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700126 method_onAgentCancel = env->GetMethodID(clazz, "onAgentCancel", "()V");
127 method_onRequestPinCode = env->GetMethodID(clazz, "onRequestPinCode",
128 "(Ljava/lang/String;I)V");
Jaikumar Ganeshb0eca412009-07-16 18:26:28 -0700129 method_onRequestPasskey = env->GetMethodID(clazz, "onRequestPasskey",
130 "(Ljava/lang/String;I)V");
Jaikumar Ganesh32d85712009-09-10 22:00:05 -0700131 method_onRequestPasskeyConfirmation = env->GetMethodID(clazz, "onRequestPasskeyConfirmation",
132 "(Ljava/lang/String;II)V");
133 method_onRequestPairingConsent = env->GetMethodID(clazz, "onRequestPairingConsent",
134 "(Ljava/lang/String;I)V");
135 method_onDisplayPasskey = env->GetMethodID(clazz, "onDisplayPasskey",
Jaikumar Ganeshb0eca412009-07-16 18:26:28 -0700136 "(Ljava/lang/String;II)V");
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700137 method_onInputDevicePropertyChanged = env->GetMethodID(clazz, "onInputDevicePropertyChanged",
Danica Chang6fdd0c62010-08-11 14:54:43 -0700138 "(Ljava/lang/String;[Ljava/lang/String;)V");
Jaikumar Ganeshde075032010-07-19 16:28:27 -0700139 method_onInputDeviceConnectionResult = env->GetMethodID(clazz, "onInputDeviceConnectionResult",
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -0800140 "(Ljava/lang/String;I)V");
Danica Chang6fdd0c62010-08-11 14:54:43 -0700141 method_onPanDevicePropertyChanged = env->GetMethodID(clazz, "onPanDevicePropertyChanged",
142 "(Ljava/lang/String;[Ljava/lang/String;)V");
143 method_onPanDeviceConnectionResult = env->GetMethodID(clazz, "onPanDeviceConnectionResult",
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -0800144 "(Ljava/lang/String;I)V");
Jaikumar Ganeshb5d2d452011-09-07 14:16:52 -0700145 method_onHealthDeviceConnectionResult = env->GetMethodID(clazz,
146 "onHealthDeviceConnectionResult",
147 "(II)V");
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700148 method_onHealthDevicePropertyChanged = env->GetMethodID(clazz, "onHealthDevicePropertyChanged",
149 "(Ljava/lang/String;[Ljava/lang/String;)V");
150 method_onHealthDeviceChannelChanged = env->GetMethodID(clazz, "onHealthDeviceChannelChanged",
151 "(Ljava/lang/String;Ljava/lang/String;Z)V");
Jaikumar Ganeshcc5494c2010-09-09 15:37:57 -0700152 method_onRequestOobData = env->GetMethodID(clazz, "onRequestOobData",
153 "(Ljava/lang/String;I)V");
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700154
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800155 field_mNativeData = env->GetFieldID(clazz, "mNativeData", "I");
156#endif
157}
158
159static void initializeNativeDataNative(JNIEnv* env, jobject object) {
Steve Block71f2cf12011-10-20 11:56:00 +0100160 ALOGV("%s", __FUNCTION__);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800161#ifdef HAVE_BLUETOOTH
162 native_data_t *nat = (native_data_t *)calloc(1, sizeof(native_data_t));
163 if (NULL == nat) {
164 LOGE("%s: out of memory!", __FUNCTION__);
165 return;
166 }
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700167 memset(nat, 0, sizeof(native_data_t));
168
169 pthread_mutex_init(&(nat->thread_mutex), NULL);
170
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800171 env->SetIntField(object, field_mNativeData, (jint)nat);
172
173 {
174 DBusError err;
175 dbus_error_init(&err);
176 dbus_threads_init_default();
177 nat->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
178 if (dbus_error_is_set(&err)) {
179 LOGE("%s: Could not get onto the system bus!", __FUNCTION__);
180 dbus_error_free(&err);
181 }
Nick Pelly9e0a1952009-06-17 15:27:59 -0700182 dbus_connection_set_exit_on_disconnect(nat->conn, FALSE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800183 }
184#endif
185}
186
187static void cleanupNativeDataNative(JNIEnv* env, jobject object) {
Steve Block71f2cf12011-10-20 11:56:00 +0100188 ALOGV("%s", __FUNCTION__);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800189#ifdef HAVE_BLUETOOTH
190 native_data_t *nat =
191 (native_data_t *)env->GetIntField(object, field_mNativeData);
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700192
193 pthread_mutex_destroy(&(nat->thread_mutex));
194
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195 if (nat) {
196 free(nat);
197 }
198#endif
199}
200
201#ifdef HAVE_BLUETOOTH
202static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg,
203 void *data);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700204DBusHandlerResult agent_event_filter(DBusConnection *conn,
205 DBusMessage *msg,
206 void *data);
207static int register_agent(native_data_t *nat,
208 const char *agent_path, const char *capabilities);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800209
210static const DBusObjectPathVTable agent_vtable = {
211 NULL, agent_event_filter, NULL, NULL, NULL, NULL
212};
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800213
Nick Pelly4a364132009-06-18 15:05:34 -0700214static unsigned int unix_events_to_dbus_flags(short events) {
215 return (events & DBUS_WATCH_READABLE ? POLLIN : 0) |
216 (events & DBUS_WATCH_WRITABLE ? POLLOUT : 0) |
217 (events & DBUS_WATCH_ERROR ? POLLERR : 0) |
218 (events & DBUS_WATCH_HANGUP ? POLLHUP : 0);
219}
220
221static short dbus_flags_to_unix_events(unsigned int flags) {
222 return (flags & POLLIN ? DBUS_WATCH_READABLE : 0) |
223 (flags & POLLOUT ? DBUS_WATCH_WRITABLE : 0) |
224 (flags & POLLERR ? DBUS_WATCH_ERROR : 0) |
225 (flags & POLLHUP ? DBUS_WATCH_HANGUP : 0);
226}
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700227
228static jboolean setUpEventLoop(native_data_t *nat) {
Steve Block71f2cf12011-10-20 11:56:00 +0100229 ALOGV("%s", __FUNCTION__);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800230
231 if (nat != NULL && nat->conn != NULL) {
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700232 dbus_threads_init_default();
233 DBusError err;
234 dbus_error_init(&err);
235
hyungseoung.yoo5ec09722011-08-05 23:01:56 -0700236 const char *agent_path = "/android/bluetooth/agent";
237 const char *capabilities = "DisplayYesNo";
238 if (register_agent(nat, agent_path, capabilities) < 0) {
239 dbus_connection_unregister_object_path (nat->conn, agent_path);
240 return JNI_FALSE;
241 }
242
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800243 // Add a filter for all incoming messages
244 if (!dbus_connection_add_filter(nat->conn, event_filter, nat, NULL)){
245 return JNI_FALSE;
246 }
247
248 // Set which messages will be processed by this dbus connection
249 dbus_bus_add_match(nat->conn,
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700250 "type='signal',interface='org.freedesktop.DBus'",
251 &err);
252 if (dbus_error_is_set(&err)) {
253 LOG_AND_FREE_DBUS_ERROR(&err);
254 return JNI_FALSE;
255 }
256 dbus_bus_add_match(nat->conn,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800257 "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".Adapter'",
258 &err);
259 if (dbus_error_is_set(&err)) {
260 LOG_AND_FREE_DBUS_ERROR(&err);
261 return JNI_FALSE;
262 }
263 dbus_bus_add_match(nat->conn,
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700264 "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".Device'",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800265 &err);
266 if (dbus_error_is_set(&err)) {
267 LOG_AND_FREE_DBUS_ERROR(&err);
268 return JNI_FALSE;
269 }
270 dbus_bus_add_match(nat->conn,
Jaikumar Ganesh56d26132010-07-15 15:56:04 -0700271 "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".Input'",
272 &err);
273 if (dbus_error_is_set(&err)) {
274 LOG_AND_FREE_DBUS_ERROR(&err);
275 return JNI_FALSE;
276 }
277 dbus_bus_add_match(nat->conn,
278 "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".Network'",
279 &err);
280 if (dbus_error_is_set(&err)) {
281 LOG_AND_FREE_DBUS_ERROR(&err);
282 return JNI_FALSE;
283 }
284 dbus_bus_add_match(nat->conn,
Jaikumar Ganeshc1520ec2010-08-31 19:55:10 -0700285 "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".NetworkServer'",
286 &err);
287 if (dbus_error_is_set(&err)) {
288 LOG_AND_FREE_DBUS_ERROR(&err);
289 return JNI_FALSE;
290 }
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700291
292 dbus_bus_add_match(nat->conn,
293 "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".HealthDevice'",
294 &err);
295 if (dbus_error_is_set(&err)) {
296 LOG_AND_FREE_DBUS_ERROR(&err);
297 return JNI_FALSE;
298 }
299
Jaikumar Ganeshc1520ec2010-08-31 19:55:10 -0700300 dbus_bus_add_match(nat->conn,
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700301 "type='signal',interface='org.bluez.AudioSink'",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800302 &err);
303 if (dbus_error_is_set(&err)) {
304 LOG_AND_FREE_DBUS_ERROR(&err);
305 return JNI_FALSE;
306 }
307
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800308 return JNI_TRUE;
309 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800310 return JNI_FALSE;
311}
312
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700313
314const char * get_adapter_path(DBusConnection *conn) {
Jaikumar Ganesh32d85712009-09-10 22:00:05 -0700315 DBusMessage *msg = NULL, *reply = NULL;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700316 DBusError err;
317 const char *device_path = NULL;
Jaikumar Ganesh176c3d62009-09-01 09:56:56 -0700318 int attempt = 0;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700319
Jaikumar Ganesh176c3d62009-09-01 09:56:56 -0700320 for (attempt = 0; attempt < 1000 && reply == NULL; attempt ++) {
321 msg = dbus_message_new_method_call("org.bluez", "/",
322 "org.bluez.Manager", "DefaultAdapter");
323 if (!msg) {
324 LOGE("%s: Can't allocate new method call for get_adapter_path!",
325 __FUNCTION__);
326 return NULL;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700327 }
Jaikumar Ganesh176c3d62009-09-01 09:56:56 -0700328 dbus_message_append_args(msg, DBUS_TYPE_INVALID);
329 dbus_error_init(&err);
330 reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
331
332 if (!reply) {
333 if (dbus_error_is_set(&err)) {
334 if (dbus_error_has_name(&err,
335 "org.freedesktop.DBus.Error.ServiceUnknown")) {
336 // bluetoothd is still down, retry
337 LOG_AND_FREE_DBUS_ERROR(&err);
338 usleep(10000); // 10 ms
339 continue;
340 } else {
341 // Some other error we weren't expecting
342 LOG_AND_FREE_DBUS_ERROR(&err);
343 }
344 }
345 goto failed;
346 }
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700347 }
Jaikumar Ganesh176c3d62009-09-01 09:56:56 -0700348 if (attempt == 1000) {
349 LOGE("Time out while trying to get Adapter path, is bluetoothd up ?");
350 goto failed;
351 }
352
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700353 if (!dbus_message_get_args(reply, &err, DBUS_TYPE_OBJECT_PATH,
354 &device_path, DBUS_TYPE_INVALID)
355 || !device_path){
356 if (dbus_error_is_set(&err)) {
357 LOG_AND_FREE_DBUS_ERROR(&err);
358 }
Jaikumar Ganesh176c3d62009-09-01 09:56:56 -0700359 goto failed;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700360 }
Jaikumar Ganesh176c3d62009-09-01 09:56:56 -0700361 dbus_message_unref(msg);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700362 return device_path;
Jaikumar Ganesh176c3d62009-09-01 09:56:56 -0700363
364failed:
365 dbus_message_unref(msg);
366 return NULL;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700367}
368
369static int register_agent(native_data_t *nat,
370 const char * agent_path, const char * capabilities)
371{
372 DBusMessage *msg, *reply;
373 DBusError err;
Nicu Pavel75d14c32011-05-05 13:11:12 +0300374 dbus_bool_t oob = TRUE;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700375
376 if (!dbus_connection_register_object_path(nat->conn, agent_path,
377 &agent_vtable, nat)) {
378 LOGE("%s: Can't register object path %s for agent!",
379 __FUNCTION__, agent_path);
380 return -1;
381 }
382
383 nat->adapter = get_adapter_path(nat->conn);
Jaikumar Ganesh176c3d62009-09-01 09:56:56 -0700384 if (nat->adapter == NULL) {
385 return -1;
386 }
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700387 msg = dbus_message_new_method_call("org.bluez", nat->adapter,
388 "org.bluez.Adapter", "RegisterAgent");
389 if (!msg) {
390 LOGE("%s: Can't allocate new method call for agent!",
391 __FUNCTION__);
392 return -1;
393 }
394 dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &agent_path,
395 DBUS_TYPE_STRING, &capabilities,
396 DBUS_TYPE_INVALID);
397
398 dbus_error_init(&err);
399 reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err);
400 dbus_message_unref(msg);
401
402 if (!reply) {
403 LOGE("%s: Can't register agent!", __FUNCTION__);
404 if (dbus_error_is_set(&err)) {
405 LOG_AND_FREE_DBUS_ERROR(&err);
406 }
407 return -1;
408 }
409
410 dbus_message_unref(reply);
411 dbus_connection_flush(nat->conn);
412
413 return 0;
414}
415
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700416static void tearDownEventLoop(native_data_t *nat) {
Steve Block71f2cf12011-10-20 11:56:00 +0100417 ALOGV("%s", __FUNCTION__);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800418 if (nat != NULL && nat->conn != NULL) {
419
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700420 DBusMessage *msg, *reply;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800421 DBusError err;
422 dbus_error_init(&err);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700423 const char * agent_path = "/android/bluetooth/agent";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800424
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700425 msg = dbus_message_new_method_call("org.bluez",
426 nat->adapter,
427 "org.bluez.Adapter",
428 "UnregisterAgent");
Jaikumar Ganesh9b0fe602009-06-11 15:10:45 -0700429 if (msg != NULL) {
430 dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &agent_path,
431 DBUS_TYPE_INVALID);
432 reply = dbus_connection_send_with_reply_and_block(nat->conn,
433 msg, -1, &err);
434
435 if (!reply) {
436 if (dbus_error_is_set(&err)) {
437 LOG_AND_FREE_DBUS_ERROR(&err);
438 dbus_error_free(&err);
439 }
440 } else {
441 dbus_message_unref(reply);
442 }
443 dbus_message_unref(msg);
444 } else {
445 LOGE("%s: Can't create new method call!", __FUNCTION__);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700446 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800447
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700448 dbus_connection_flush(nat->conn);
449 dbus_connection_unregister_object_path(nat->conn, agent_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800450
451 dbus_bus_remove_match(nat->conn,
Jaikumar Ganeshc1520ec2010-08-31 19:55:10 -0700452 "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".AudioSink'",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800453 &err);
454 if (dbus_error_is_set(&err)) {
455 LOG_AND_FREE_DBUS_ERROR(&err);
456 }
457 dbus_bus_remove_match(nat->conn,
Jaikumar Ganeshc1520ec2010-08-31 19:55:10 -0700458 "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".Device'",
459 &err);
460 if (dbus_error_is_set(&err)) {
461 LOG_AND_FREE_DBUS_ERROR(&err);
462 }
463 dbus_bus_remove_match(nat->conn,
464 "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".Input'",
465 &err);
466 if (dbus_error_is_set(&err)) {
467 LOG_AND_FREE_DBUS_ERROR(&err);
468 }
469 dbus_bus_remove_match(nat->conn,
470 "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".Network'",
471 &err);
472 if (dbus_error_is_set(&err)) {
473 LOG_AND_FREE_DBUS_ERROR(&err);
474 }
475 dbus_bus_remove_match(nat->conn,
476 "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".NetworkServer'",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800477 &err);
478 if (dbus_error_is_set(&err)) {
479 LOG_AND_FREE_DBUS_ERROR(&err);
480 }
481 dbus_bus_remove_match(nat->conn,
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700482 "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".HealthDevice'",
483 &err);
484 if (dbus_error_is_set(&err)) {
485 LOG_AND_FREE_DBUS_ERROR(&err);
486 }
487 dbus_bus_remove_match(nat->conn,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800488 "type='signal',interface='org.bluez.audio.Manager'",
489 &err);
490 if (dbus_error_is_set(&err)) {
491 LOG_AND_FREE_DBUS_ERROR(&err);
492 }
493 dbus_bus_remove_match(nat->conn,
494 "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".Adapter'",
495 &err);
496 if (dbus_error_is_set(&err)) {
497 LOG_AND_FREE_DBUS_ERROR(&err);
498 }
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700499 dbus_bus_remove_match(nat->conn,
500 "type='signal',interface='org.freedesktop.DBus'",
501 &err);
502 if (dbus_error_is_set(&err)) {
503 LOG_AND_FREE_DBUS_ERROR(&err);
504 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800505
506 dbus_connection_remove_filter(nat->conn, event_filter, nat);
507 }
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700508}
509
510
511#define EVENT_LOOP_EXIT 1
512#define EVENT_LOOP_ADD 2
513#define EVENT_LOOP_REMOVE 3
Albert Mojirf4c64042011-06-20 16:14:13 +0200514#define EVENT_LOOP_WAKEUP 4
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700515
516dbus_bool_t dbusAddWatch(DBusWatch *watch, void *data) {
517 native_data_t *nat = (native_data_t *)data;
518
519 if (dbus_watch_get_enabled(watch)) {
520 // note that we can't just send the watch and inspect it later
521 // because we may get a removeWatch call before this data is reacted
522 // to by our eventloop and remove this watch.. reading the add first
523 // and then inspecting the recently deceased watch would be bad.
524 char control = EVENT_LOOP_ADD;
525 write(nat->controlFdW, &control, sizeof(char));
526
527 int fd = dbus_watch_get_fd(watch);
528 write(nat->controlFdW, &fd, sizeof(int));
529
530 unsigned int flags = dbus_watch_get_flags(watch);
531 write(nat->controlFdW, &flags, sizeof(unsigned int));
532
533 write(nat->controlFdW, &watch, sizeof(DBusWatch*));
534 }
535 return true;
536}
537
538void dbusRemoveWatch(DBusWatch *watch, void *data) {
539 native_data_t *nat = (native_data_t *)data;
540
541 char control = EVENT_LOOP_REMOVE;
542 write(nat->controlFdW, &control, sizeof(char));
543
544 int fd = dbus_watch_get_fd(watch);
545 write(nat->controlFdW, &fd, sizeof(int));
546
547 unsigned int flags = dbus_watch_get_flags(watch);
548 write(nat->controlFdW, &flags, sizeof(unsigned int));
549}
550
551void dbusToggleWatch(DBusWatch *watch, void *data) {
552 if (dbus_watch_get_enabled(watch)) {
553 dbusAddWatch(watch, data);
554 } else {
555 dbusRemoveWatch(watch, data);
556 }
557}
558
Albert Mojirf4c64042011-06-20 16:14:13 +0200559void dbusWakeup(void *data) {
560 native_data_t *nat = (native_data_t *)data;
561
562 char control = EVENT_LOOP_WAKEUP;
563 write(nat->controlFdW, &control, sizeof(char));
564}
565
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700566static void handleWatchAdd(native_data_t *nat) {
567 DBusWatch *watch;
568 int newFD;
569 unsigned int flags;
570
571 read(nat->controlFdR, &newFD, sizeof(int));
572 read(nat->controlFdR, &flags, sizeof(unsigned int));
573 read(nat->controlFdR, &watch, sizeof(DBusWatch *));
Nick Pelly4a364132009-06-18 15:05:34 -0700574 short events = dbus_flags_to_unix_events(flags);
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700575
576 for (int y = 0; y<nat->pollMemberCount; y++) {
577 if ((nat->pollData[y].fd == newFD) &&
578 (nat->pollData[y].events == events)) {
Steve Block71f2cf12011-10-20 11:56:00 +0100579 ALOGV("DBusWatch duplicate add");
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700580 return;
581 }
582 }
583 if (nat->pollMemberCount == nat->pollDataSize) {
Steve Block71f2cf12011-10-20 11:56:00 +0100584 ALOGV("Bluetooth EventLoop poll struct growing");
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700585 struct pollfd *temp = (struct pollfd *)malloc(
586 sizeof(struct pollfd) * (nat->pollMemberCount+1));
587 if (!temp) {
588 return;
589 }
590 memcpy(temp, nat->pollData, sizeof(struct pollfd) *
591 nat->pollMemberCount);
592 free(nat->pollData);
593 nat->pollData = temp;
594 DBusWatch **temp2 = (DBusWatch **)malloc(sizeof(DBusWatch *) *
595 (nat->pollMemberCount+1));
596 if (!temp2) {
597 return;
598 }
599 memcpy(temp2, nat->watchData, sizeof(DBusWatch *) *
600 nat->pollMemberCount);
601 free(nat->watchData);
602 nat->watchData = temp2;
603 nat->pollDataSize++;
604 }
605 nat->pollData[nat->pollMemberCount].fd = newFD;
606 nat->pollData[nat->pollMemberCount].revents = 0;
607 nat->pollData[nat->pollMemberCount].events = events;
608 nat->watchData[nat->pollMemberCount] = watch;
609 nat->pollMemberCount++;
610}
611
612static void handleWatchRemove(native_data_t *nat) {
613 int removeFD;
614 unsigned int flags;
615
616 read(nat->controlFdR, &removeFD, sizeof(int));
617 read(nat->controlFdR, &flags, sizeof(unsigned int));
Nick Pelly4a364132009-06-18 15:05:34 -0700618 short events = dbus_flags_to_unix_events(flags);
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700619
620 for (int y = 0; y < nat->pollMemberCount; y++) {
621 if ((nat->pollData[y].fd == removeFD) &&
622 (nat->pollData[y].events == events)) {
623 int newCount = --nat->pollMemberCount;
624 // copy the last live member over this one
625 nat->pollData[y].fd = nat->pollData[newCount].fd;
626 nat->pollData[y].events = nat->pollData[newCount].events;
627 nat->pollData[y].revents = nat->pollData[newCount].revents;
628 nat->watchData[y] = nat->watchData[newCount];
629 return;
630 }
631 }
632 LOGW("WatchRemove given with unknown watch");
633}
634
635static void *eventLoopMain(void *ptr) {
636 native_data_t *nat = (native_data_t *)ptr;
637 JNIEnv *env;
638
639 JavaVMAttachArgs args;
640 char name[] = "BT EventLoop";
641 args.version = nat->envVer;
642 args.name = name;
643 args.group = NULL;
644
645 nat->vm->AttachCurrentThread(&env, &args);
646
647 dbus_connection_set_watch_functions(nat->conn, dbusAddWatch,
648 dbusRemoveWatch, dbusToggleWatch, ptr, NULL);
Albert Mojirf4c64042011-06-20 16:14:13 +0200649 dbus_connection_set_wakeup_main_function(nat->conn, dbusWakeup, ptr, NULL);
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700650
Jaikumar Ganeshb8aa0372010-03-31 11:23:49 -0700651 nat->running = true;
652
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700653 while (1) {
654 for (int i = 0; i < nat->pollMemberCount; i++) {
655 if (!nat->pollData[i].revents) {
656 continue;
657 }
658 if (nat->pollData[i].fd == nat->controlFdR) {
659 char data;
660 while (recv(nat->controlFdR, &data, sizeof(char), MSG_DONTWAIT)
661 != -1) {
662 switch (data) {
663 case EVENT_LOOP_EXIT:
664 {
665 dbus_connection_set_watch_functions(nat->conn,
666 NULL, NULL, NULL, NULL, NULL);
667 tearDownEventLoop(nat);
668 nat->vm->DetachCurrentThread();
Johannes Carlssoned0d1ab2010-03-08 10:19:31 +0100669
670 int fd = nat->controlFdR;
671 nat->controlFdR = 0;
672 close(fd);
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700673 return NULL;
674 }
675 case EVENT_LOOP_ADD:
676 {
677 handleWatchAdd(nat);
678 break;
679 }
680 case EVENT_LOOP_REMOVE:
681 {
682 handleWatchRemove(nat);
683 break;
684 }
Albert Mojirf4c64042011-06-20 16:14:13 +0200685 case EVENT_LOOP_WAKEUP:
686 {
687 // noop
688 break;
689 }
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700690 }
691 }
692 } else {
Nick Pelly4a364132009-06-18 15:05:34 -0700693 short events = nat->pollData[i].revents;
694 unsigned int flags = unix_events_to_dbus_flags(events);
695 dbus_watch_handle(nat->watchData[i], flags);
696 nat->pollData[i].revents = 0;
697 // can only do one - it may have caused a 'remove'
698 break;
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700699 }
700 }
Jaikumar Ganeshb8aa0372010-03-31 11:23:49 -0700701 while (dbus_connection_dispatch(nat->conn) ==
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700702 DBUS_DISPATCH_DATA_REMAINS) {
703 }
704
705 poll(nat->pollData, nat->pollMemberCount, -1);
706 }
707}
708#endif // HAVE_BLUETOOTH
709
710static jboolean startEventLoopNative(JNIEnv *env, jobject object) {
711 jboolean result = JNI_FALSE;
712#ifdef HAVE_BLUETOOTH
713 event_loop_native_data_t *nat = get_native_data(env, object);
714
715 pthread_mutex_lock(&(nat->thread_mutex));
716
Jaikumar Ganeshb8aa0372010-03-31 11:23:49 -0700717 nat->running = false;
718
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700719 if (nat->pollData) {
720 LOGW("trying to start EventLoop a second time!");
721 pthread_mutex_unlock( &(nat->thread_mutex) );
722 return JNI_FALSE;
723 }
724
725 nat->pollData = (struct pollfd *)malloc(sizeof(struct pollfd) *
726 DEFAULT_INITIAL_POLLFD_COUNT);
727 if (!nat->pollData) {
728 LOGE("out of memory error starting EventLoop!");
729 goto done;
730 }
731
732 nat->watchData = (DBusWatch **)malloc(sizeof(DBusWatch *) *
733 DEFAULT_INITIAL_POLLFD_COUNT);
734 if (!nat->watchData) {
735 LOGE("out of memory error starting EventLoop!");
736 goto done;
737 }
738
739 memset(nat->pollData, 0, sizeof(struct pollfd) *
740 DEFAULT_INITIAL_POLLFD_COUNT);
741 memset(nat->watchData, 0, sizeof(DBusWatch *) *
742 DEFAULT_INITIAL_POLLFD_COUNT);
743 nat->pollDataSize = DEFAULT_INITIAL_POLLFD_COUNT;
744 nat->pollMemberCount = 1;
745
746 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, &(nat->controlFdR))) {
747 LOGE("Error getting BT control socket");
748 goto done;
749 }
750 nat->pollData[0].fd = nat->controlFdR;
751 nat->pollData[0].events = POLLIN;
752
753 env->GetJavaVM( &(nat->vm) );
754 nat->envVer = env->GetVersion();
755
756 nat->me = env->NewGlobalRef(object);
757
758 if (setUpEventLoop(nat) != JNI_TRUE) {
759 LOGE("failure setting up Event Loop!");
760 goto done;
761 }
762
763 pthread_create(&(nat->thread), NULL, eventLoopMain, nat);
764 result = JNI_TRUE;
765
766done:
767 if (JNI_FALSE == result) {
Johannes Carlssoned0d1ab2010-03-08 10:19:31 +0100768 if (nat->controlFdW) {
769 close(nat->controlFdW);
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700770 nat->controlFdW = 0;
Johannes Carlssoned0d1ab2010-03-08 10:19:31 +0100771 }
772 if (nat->controlFdR) {
773 close(nat->controlFdR);
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700774 nat->controlFdR = 0;
775 }
776 if (nat->me) env->DeleteGlobalRef(nat->me);
777 nat->me = NULL;
778 if (nat->pollData) free(nat->pollData);
779 nat->pollData = NULL;
780 if (nat->watchData) free(nat->watchData);
781 nat->watchData = NULL;
782 nat->pollDataSize = 0;
783 nat->pollMemberCount = 0;
784 }
785
786 pthread_mutex_unlock(&(nat->thread_mutex));
787#endif // HAVE_BLUETOOTH
788 return result;
789}
790
791static void stopEventLoopNative(JNIEnv *env, jobject object) {
792#ifdef HAVE_BLUETOOTH
793 native_data_t *nat = get_native_data(env, object);
794
795 pthread_mutex_lock(&(nat->thread_mutex));
796 if (nat->pollData) {
797 char data = EVENT_LOOP_EXIT;
798 ssize_t t = write(nat->controlFdW, &data, sizeof(char));
799 void *ret;
800 pthread_join(nat->thread, &ret);
801
802 env->DeleteGlobalRef(nat->me);
803 nat->me = NULL;
804 free(nat->pollData);
805 nat->pollData = NULL;
806 free(nat->watchData);
807 nat->watchData = NULL;
808 nat->pollDataSize = 0;
809 nat->pollMemberCount = 0;
Johannes Carlssoned0d1ab2010-03-08 10:19:31 +0100810
811 int fd = nat->controlFdW;
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700812 nat->controlFdW = 0;
Johannes Carlssoned0d1ab2010-03-08 10:19:31 +0100813 close(fd);
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700814 }
Jaikumar Ganeshb8aa0372010-03-31 11:23:49 -0700815 nat->running = false;
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700816 pthread_mutex_unlock(&(nat->thread_mutex));
817#endif // HAVE_BLUETOOTH
818}
819
820static jboolean isEventLoopRunningNative(JNIEnv *env, jobject object) {
821 jboolean result = JNI_FALSE;
822#ifdef HAVE_BLUETOOTH
823 native_data_t *nat = get_native_data(env, object);
824
825 pthread_mutex_lock(&(nat->thread_mutex));
Jaikumar Ganeshb8aa0372010-03-31 11:23:49 -0700826 if (nat->running) {
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700827 result = JNI_TRUE;
828 }
829 pthread_mutex_unlock(&(nat->thread_mutex));
830
831#endif // HAVE_BLUETOOTH
832 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800833}
834
835#ifdef HAVE_BLUETOOTH
836extern DBusHandlerResult a2dp_event_filter(DBusMessage *msg, JNIEnv *env);
837
838// Called by dbus during WaitForAndDispatchEventNative()
839static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg,
840 void *data) {
841 native_data_t *nat;
842 JNIEnv *env;
843 DBusError err;
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -0700844 DBusHandlerResult ret;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800845
846 dbus_error_init(&err);
847
848 nat = (native_data_t *)data;
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700849 nat->vm->GetEnv((void**)&env, nat->envVer);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800850 if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_SIGNAL) {
Steve Block71f2cf12011-10-20 11:56:00 +0100851 ALOGV("%s: not interested (not a signal).", __FUNCTION__);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800852 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
853 }
854
Steve Block71f2cf12011-10-20 11:56:00 +0100855 ALOGV("%s: Received signal %s:%s from %s", __FUNCTION__,
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700856 dbus_message_get_interface(msg), dbus_message_get_member(msg),
857 dbus_message_get_path(msg));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800858
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -0700859 env->PushLocalFrame(EVENT_LOOP_REFS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800860 if (dbus_message_is_signal(msg,
861 "org.bluez.Adapter",
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700862 "DeviceFound")) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800863 char *c_address;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700864 DBusMessageIter iter;
865 jobjectArray str_array = NULL;
866 if (dbus_message_iter_init(msg, &iter)) {
867 dbus_message_iter_get_basic(&iter, &c_address);
868 if (dbus_message_iter_next(&iter))
869 str_array =
870 parse_remote_device_properties(env, &iter);
871 }
872 if (str_array != NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800873 env->CallVoidMethod(nat->me,
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700874 method_onDeviceFound,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800875 env->NewStringUTF(c_address),
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700876 str_array);
877 } else
878 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -0700879 goto success;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800880 } else if (dbus_message_is_signal(msg,
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700881 "org.bluez.Adapter",
882 "DeviceDisappeared")) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800883 char *c_address;
884 if (dbus_message_get_args(msg, &err,
885 DBUS_TYPE_STRING, &c_address,
886 DBUS_TYPE_INVALID)) {
Steve Block71f2cf12011-10-20 11:56:00 +0100887 ALOGV("... address = %s", c_address);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700888 env->CallVoidMethod(nat->me, method_onDeviceDisappeared,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800889 env->NewStringUTF(c_address));
890 } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -0700891 goto success;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800892 } else if (dbus_message_is_signal(msg,
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700893 "org.bluez.Adapter",
894 "DeviceCreated")) {
895 char *c_object_path;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800896 if (dbus_message_get_args(msg, &err,
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700897 DBUS_TYPE_OBJECT_PATH, &c_object_path,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800898 DBUS_TYPE_INVALID)) {
Steve Block71f2cf12011-10-20 11:56:00 +0100899 ALOGV("... address = %s", c_object_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800900 env->CallVoidMethod(nat->me,
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700901 method_onDeviceCreated,
902 env->NewStringUTF(c_object_path));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800903 } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -0700904 goto success;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800905 } else if (dbus_message_is_signal(msg,
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700906 "org.bluez.Adapter",
907 "DeviceRemoved")) {
908 char *c_object_path;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800909 if (dbus_message_get_args(msg, &err,
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700910 DBUS_TYPE_OBJECT_PATH, &c_object_path,
911 DBUS_TYPE_INVALID)) {
Steve Block71f2cf12011-10-20 11:56:00 +0100912 ALOGV("... Object Path = %s", c_object_path);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700913 env->CallVoidMethod(nat->me,
914 method_onDeviceRemoved,
915 env->NewStringUTF(c_object_path));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800916 } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -0700917 goto success;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700918 } else if (dbus_message_is_signal(msg,
919 "org.bluez.Adapter",
920 "PropertyChanged")) {
921 jobjectArray str_array = parse_adapter_property_change(env, msg);
922 if (str_array != NULL) {
923 /* Check if bluetoothd has (re)started, if so update the path. */
924 jstring property =(jstring) env->GetObjectArrayElement(str_array, 0);
925 const char *c_property = env->GetStringUTFChars(property, NULL);
926 if (!strncmp(c_property, "Powered", strlen("Powered"))) {
927 jstring value =
928 (jstring) env->GetObjectArrayElement(str_array, 1);
929 const char *c_value = env->GetStringUTFChars(value, NULL);
930 if (!strncmp(c_value, "true", strlen("true")))
931 nat->adapter = get_adapter_path(nat->conn);
932 env->ReleaseStringUTFChars(value, c_value);
933 }
934 env->ReleaseStringUTFChars(property, c_property);
935
936 env->CallVoidMethod(nat->me,
937 method_onPropertyChanged,
938 str_array);
939 } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -0700940 goto success;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700941 } else if (dbus_message_is_signal(msg,
942 "org.bluez.Device",
943 "PropertyChanged")) {
944 jobjectArray str_array = parse_remote_device_property_change(env, msg);
945 if (str_array != NULL) {
946 const char *remote_device_path = dbus_message_get_path(msg);
947 env->CallVoidMethod(nat->me,
948 method_onDevicePropertyChanged,
949 env->NewStringUTF(remote_device_path),
950 str_array);
951 } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -0700952 goto success;
Jaikumar Ganesh5e59ca82009-09-11 12:16:19 -0700953 } else if (dbus_message_is_signal(msg,
954 "org.bluez.Device",
955 "DisconnectRequested")) {
956 const char *remote_device_path = dbus_message_get_path(msg);
957 env->CallVoidMethod(nat->me,
958 method_onDeviceDisconnectRequested,
959 env->NewStringUTF(remote_device_path));
960 goto success;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700961 } else if (dbus_message_is_signal(msg,
962 "org.bluez.Input",
963 "PropertyChanged")) {
964
965 jobjectArray str_array =
966 parse_input_property_change(env, msg);
967 if (str_array != NULL) {
968 const char *c_path = dbus_message_get_path(msg);
969 env->CallVoidMethod(nat->me,
970 method_onInputDevicePropertyChanged,
971 env->NewStringUTF(c_path),
972 str_array);
973 } else {
974 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
975 }
976 goto success;
Danica Chang6fdd0c62010-08-11 14:54:43 -0700977 } else if (dbus_message_is_signal(msg,
978 "org.bluez.Network",
979 "PropertyChanged")) {
980
981 jobjectArray str_array =
982 parse_pan_property_change(env, msg);
983 if (str_array != NULL) {
984 const char *c_path = dbus_message_get_path(msg);
985 env->CallVoidMethod(nat->me,
986 method_onPanDevicePropertyChanged,
987 env->NewStringUTF(c_path),
988 str_array);
989 } else {
990 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
991 }
992 goto success;
Jaikumar Ganeshc1520ec2010-08-31 19:55:10 -0700993 } else if (dbus_message_is_signal(msg,
994 "org.bluez.NetworkServer",
995 "DeviceDisconnected")) {
996 char *c_address;
997 if (dbus_message_get_args(msg, &err,
998 DBUS_TYPE_STRING, &c_address,
999 DBUS_TYPE_INVALID)) {
1000 env->CallVoidMethod(nat->me,
1001 method_onNetworkDeviceDisconnected,
1002 env->NewStringUTF(c_address));
1003 } else {
1004 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
1005 }
1006 goto success;
1007 } else if (dbus_message_is_signal(msg,
1008 "org.bluez.NetworkServer",
1009 "DeviceConnected")) {
1010 char *c_address;
Jaikumar Ganesh707952e2010-09-13 19:04:54 -07001011 char *c_iface;
Jaikumar Ganeshc1520ec2010-08-31 19:55:10 -07001012 uint16_t uuid;
1013
1014 if (dbus_message_get_args(msg, &err,
1015 DBUS_TYPE_STRING, &c_address,
Jaikumar Ganesh707952e2010-09-13 19:04:54 -07001016 DBUS_TYPE_STRING, &c_iface,
Jaikumar Ganeshc1520ec2010-08-31 19:55:10 -07001017 DBUS_TYPE_UINT16, &uuid,
1018 DBUS_TYPE_INVALID)) {
1019 env->CallVoidMethod(nat->me,
1020 method_onNetworkDeviceConnected,
1021 env->NewStringUTF(c_address),
Jaikumar Ganesh707952e2010-09-13 19:04:54 -07001022 env->NewStringUTF(c_iface),
Jaikumar Ganeshc1520ec2010-08-31 19:55:10 -07001023 uuid);
1024 } else {
1025 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
1026 }
1027 goto success;
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -07001028 } else if (dbus_message_is_signal(msg,
1029 "org.bluez.HealthDevice",
1030 "ChannelConnected")) {
1031 const char *c_path = dbus_message_get_path(msg);
1032 const char *c_channel_path;
1033 jboolean exists = JNI_TRUE;
1034 if (dbus_message_get_args(msg, &err,
1035 DBUS_TYPE_OBJECT_PATH, &c_channel_path,
1036 DBUS_TYPE_INVALID)) {
1037 env->CallVoidMethod(nat->me,
1038 method_onHealthDeviceChannelChanged,
1039 env->NewStringUTF(c_path),
1040 env->NewStringUTF(c_channel_path),
1041 exists);
1042 } else {
1043 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
1044 }
1045 goto success;
1046 } else if (dbus_message_is_signal(msg,
Jaikumar Ganeshae37d062011-08-20 18:15:16 -07001047 "org.bluez.HealthDevice",
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -07001048 "ChannelDeleted")) {
1049
1050 const char *c_path = dbus_message_get_path(msg);
1051 const char *c_channel_path;
1052 jboolean exists = JNI_FALSE;
1053 if (dbus_message_get_args(msg, &err,
1054 DBUS_TYPE_OBJECT_PATH, &c_channel_path,
1055 DBUS_TYPE_INVALID)) {
1056 env->CallVoidMethod(nat->me,
1057 method_onHealthDeviceChannelChanged,
1058 env->NewStringUTF(c_path),
1059 env->NewStringUTF(c_channel_path),
1060 exists);
1061 } else {
1062 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
1063 }
1064 goto success;
1065 } else if (dbus_message_is_signal(msg,
1066 "org.bluez.HealthDevice",
1067 "PropertyChanged")) {
1068 jobjectArray str_array =
1069 parse_health_device_property_change(env, msg);
1070 if (str_array != NULL) {
1071 const char *c_path = dbus_message_get_path(msg);
1072 env->CallVoidMethod(nat->me,
1073 method_onHealthDevicePropertyChanged,
1074 env->NewStringUTF(c_path),
1075 str_array);
1076 } else {
1077 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
1078 }
1079 goto success;
Jaikumar Ganeshc1520ec2010-08-31 19:55:10 -07001080 }
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -07001081
1082 ret = a2dp_event_filter(msg, env);
1083 env->PopLocalFrame(NULL);
1084 return ret;
1085
1086success:
1087 env->PopLocalFrame(NULL);
1088 return DBUS_HANDLER_RESULT_HANDLED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001089}
1090
1091// Called by dbus during WaitForAndDispatchEventNative()
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -07001092DBusHandlerResult agent_event_filter(DBusConnection *conn,
1093 DBusMessage *msg, void *data) {
Robert Greenwalt28d139f2009-04-02 22:41:08 -07001094 native_data_t *nat = (native_data_t *)data;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001095 JNIEnv *env;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001096 if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_METHOD_CALL) {
Steve Block71f2cf12011-10-20 11:56:00 +01001097 ALOGV("%s: not interested (not a method call).", __FUNCTION__);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001098 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1099 }
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -07001100 LOGI("%s: Received method %s:%s", __FUNCTION__,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001101 dbus_message_get_interface(msg), dbus_message_get_member(msg));
1102
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -07001103 if (nat == NULL) return DBUS_HANDLER_RESULT_HANDLED;
1104
1105 nat->vm->GetEnv((void**)&env, nat->envVer);
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -07001106 env->PushLocalFrame(EVENT_LOOP_REFS);
1107
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001108 if (dbus_message_is_method_call(msg,
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -07001109 "org.bluez.Agent", "Cancel")) {
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -07001110 env->CallVoidMethod(nat->me, method_onAgentCancel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001111 // reply
1112 DBusMessage *reply = dbus_message_new_method_return(msg);
1113 if (!reply) {
1114 LOGE("%s: Cannot create message reply\n", __FUNCTION__);
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -07001115 goto failure;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001116 }
1117 dbus_connection_send(nat->conn, reply, NULL);
1118 dbus_message_unref(reply);
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -07001119 goto success;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001120
1121 } else if (dbus_message_is_method_call(msg,
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -07001122 "org.bluez.Agent", "Authorize")) {
1123 char *object_path;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001124 const char *uuid;
1125 if (!dbus_message_get_args(msg, NULL,
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -07001126 DBUS_TYPE_OBJECT_PATH, &object_path,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001127 DBUS_TYPE_STRING, &uuid,
1128 DBUS_TYPE_INVALID)) {
1129 LOGE("%s: Invalid arguments for Authorize() method", __FUNCTION__);
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -07001130 goto failure;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001131 }
1132
Steve Block71f2cf12011-10-20 11:56:00 +01001133 ALOGV("... object_path = %s", object_path);
1134 ALOGV("... uuid = %s", uuid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001135
Matthew Xiea0c68032011-06-25 21:47:07 -07001136 dbus_message_ref(msg); // increment refcount because we pass to java
Jeff Brown14fcf902011-07-14 03:54:36 -07001137 env->CallVoidMethod(nat->me, method_onAgentAuthorize,
Matthew Xiea0c68032011-06-25 21:47:07 -07001138 env->NewStringUTF(object_path), env->NewStringUTF(uuid),
1139 int(msg));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001140
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -07001141 goto success;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001142 } else if (dbus_message_is_method_call(msg,
Jaikumar Ganeshcc5494c2010-09-09 15:37:57 -07001143 "org.bluez.Agent", "OutOfBandAvailable")) {
1144 char *object_path;
1145 if (!dbus_message_get_args(msg, NULL,
1146 DBUS_TYPE_OBJECT_PATH, &object_path,
1147 DBUS_TYPE_INVALID)) {
1148 LOGE("%s: Invalid arguments for OutOfBandData available() method", __FUNCTION__);
1149 goto failure;
1150 }
1151
Steve Block71f2cf12011-10-20 11:56:00 +01001152 ALOGV("... object_path = %s", object_path);
Jaikumar Ganeshcc5494c2010-09-09 15:37:57 -07001153
1154 bool available =
1155 env->CallBooleanMethod(nat->me, method_onAgentOutOfBandDataAvailable,
1156 env->NewStringUTF(object_path));
1157
1158
1159 // reply
1160 if (available) {
1161 DBusMessage *reply = dbus_message_new_method_return(msg);
1162 if (!reply) {
1163 LOGE("%s: Cannot create message reply\n", __FUNCTION__);
1164 goto failure;
1165 }
1166 dbus_connection_send(nat->conn, reply, NULL);
1167 dbus_message_unref(reply);
1168 } else {
1169 DBusMessage *reply = dbus_message_new_error(msg,
1170 "org.bluez.Error.DoesNotExist", "OutofBand data not available");
1171 if (!reply) {
1172 LOGE("%s: Cannot create message reply\n", __FUNCTION__);
1173 goto failure;
1174 }
1175 dbus_connection_send(nat->conn, reply, NULL);
1176 dbus_message_unref(reply);
1177 }
1178 goto success;
1179 } else if (dbus_message_is_method_call(msg,
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -07001180 "org.bluez.Agent", "RequestPinCode")) {
1181 char *object_path;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001182 if (!dbus_message_get_args(msg, NULL,
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -07001183 DBUS_TYPE_OBJECT_PATH, &object_path,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001184 DBUS_TYPE_INVALID)) {
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -07001185 LOGE("%s: Invalid arguments for RequestPinCode() method", __FUNCTION__);
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -07001186 goto failure;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001187 }
1188
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -07001189 dbus_message_ref(msg); // increment refcount because we pass to java
1190 env->CallVoidMethod(nat->me, method_onRequestPinCode,
1191 env->NewStringUTF(object_path),
1192 int(msg));
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -07001193 goto success;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001194 } else if (dbus_message_is_method_call(msg,
Jaikumar Ganeshb0eca412009-07-16 18:26:28 -07001195 "org.bluez.Agent", "RequestPasskey")) {
1196 char *object_path;
1197 if (!dbus_message_get_args(msg, NULL,
1198 DBUS_TYPE_OBJECT_PATH, &object_path,
1199 DBUS_TYPE_INVALID)) {
1200 LOGE("%s: Invalid arguments for RequestPasskey() method", __FUNCTION__);
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -07001201 goto failure;
Jaikumar Ganeshb0eca412009-07-16 18:26:28 -07001202 }
1203
1204 dbus_message_ref(msg); // increment refcount because we pass to java
1205 env->CallVoidMethod(nat->me, method_onRequestPasskey,
1206 env->NewStringUTF(object_path),
1207 int(msg));
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -07001208 goto success;
Jaikumar Ganeshb0eca412009-07-16 18:26:28 -07001209 } else if (dbus_message_is_method_call(msg,
Jaikumar Ganeshcc5494c2010-09-09 15:37:57 -07001210 "org.bluez.Agent", "RequestOobData")) {
1211 char *object_path;
1212 if (!dbus_message_get_args(msg, NULL,
1213 DBUS_TYPE_OBJECT_PATH, &object_path,
1214 DBUS_TYPE_INVALID)) {
1215 LOGE("%s: Invalid arguments for RequestOobData() method", __FUNCTION__);
1216 goto failure;
1217 }
1218
1219 dbus_message_ref(msg); // increment refcount because we pass to java
1220 env->CallVoidMethod(nat->me, method_onRequestOobData,
1221 env->NewStringUTF(object_path),
1222 int(msg));
1223 goto success;
1224 } else if (dbus_message_is_method_call(msg,
Jaikumar Ganesh32d85712009-09-10 22:00:05 -07001225 "org.bluez.Agent", "DisplayPasskey")) {
1226 char *object_path;
1227 uint32_t passkey;
1228 if (!dbus_message_get_args(msg, NULL,
1229 DBUS_TYPE_OBJECT_PATH, &object_path,
1230 DBUS_TYPE_UINT32, &passkey,
1231 DBUS_TYPE_INVALID)) {
1232 LOGE("%s: Invalid arguments for RequestPasskey() method", __FUNCTION__);
1233 goto failure;
1234 }
1235
1236 dbus_message_ref(msg); // increment refcount because we pass to java
1237 env->CallVoidMethod(nat->me, method_onDisplayPasskey,
1238 env->NewStringUTF(object_path),
1239 passkey,
1240 int(msg));
1241 goto success;
1242 } else if (dbus_message_is_method_call(msg,
Jaikumar Ganeshb0eca412009-07-16 18:26:28 -07001243 "org.bluez.Agent", "RequestConfirmation")) {
1244 char *object_path;
1245 uint32_t passkey;
1246 if (!dbus_message_get_args(msg, NULL,
1247 DBUS_TYPE_OBJECT_PATH, &object_path,
1248 DBUS_TYPE_UINT32, &passkey,
1249 DBUS_TYPE_INVALID)) {
1250 LOGE("%s: Invalid arguments for RequestConfirmation() method", __FUNCTION__);
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -07001251 goto failure;
Jaikumar Ganeshb0eca412009-07-16 18:26:28 -07001252 }
1253
1254 dbus_message_ref(msg); // increment refcount because we pass to java
Jaikumar Ganesh32d85712009-09-10 22:00:05 -07001255 env->CallVoidMethod(nat->me, method_onRequestPasskeyConfirmation,
Jaikumar Ganeshb0eca412009-07-16 18:26:28 -07001256 env->NewStringUTF(object_path),
1257 passkey,
1258 int(msg));
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -07001259 goto success;
Jaikumar Ganeshb0eca412009-07-16 18:26:28 -07001260 } else if (dbus_message_is_method_call(msg,
Jaikumar Ganesh32d85712009-09-10 22:00:05 -07001261 "org.bluez.Agent", "RequestPairingConsent")) {
1262 char *object_path;
1263 if (!dbus_message_get_args(msg, NULL,
1264 DBUS_TYPE_OBJECT_PATH, &object_path,
1265 DBUS_TYPE_INVALID)) {
1266 LOGE("%s: Invalid arguments for RequestPairingConsent() method", __FUNCTION__);
1267 goto failure;
1268 }
1269
1270 dbus_message_ref(msg); // increment refcount because we pass to java
1271 env->CallVoidMethod(nat->me, method_onRequestPairingConsent,
1272 env->NewStringUTF(object_path),
1273 int(msg));
1274 goto success;
1275 } else if (dbus_message_is_method_call(msg,
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -07001276 "org.bluez.Agent", "Release")) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001277 // reply
1278 DBusMessage *reply = dbus_message_new_method_return(msg);
1279 if (!reply) {
1280 LOGE("%s: Cannot create message reply\n", __FUNCTION__);
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -07001281 goto failure;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001282 }
1283 dbus_connection_send(nat->conn, reply, NULL);
1284 dbus_message_unref(reply);
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -07001285 goto success;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001286 } else {
Steve Block71f2cf12011-10-20 11:56:00 +01001287 ALOGV("%s:%s is ignored", dbus_message_get_interface(msg), dbus_message_get_member(msg));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001288 }
1289
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -07001290failure:
1291 env->PopLocalFrame(NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001292 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
Jaikumar Ganesh6d56b532009-08-24 17:11:11 -07001293
1294success:
1295 env->PopLocalFrame(NULL);
1296 return DBUS_HANDLER_RESULT_HANDLED;
1297
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001298}
1299#endif
1300
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001301
1302#ifdef HAVE_BLUETOOTH
Robert Greenwalt28d139f2009-04-02 22:41:08 -07001303
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -07001304void onCreatePairedDeviceResult(DBusMessage *msg, void *user, void *n) {
Steve Block71f2cf12011-10-20 11:56:00 +01001305 ALOGV("%s", __FUNCTION__);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001306
Robert Greenwalt28d139f2009-04-02 22:41:08 -07001307 native_data_t *nat = (native_data_t *)n;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001308 const char *address = (const char *)user;
1309 DBusError err;
1310 dbus_error_init(&err);
Robert Greenwalt28d139f2009-04-02 22:41:08 -07001311 JNIEnv *env;
Jaikumar Ganesha7c0bdc2010-06-03 16:50:57 -07001312 jstring addr;
1313
Robert Greenwalt28d139f2009-04-02 22:41:08 -07001314 nat->vm->GetEnv((void**)&env, nat->envVer);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001315
Steve Block71f2cf12011-10-20 11:56:00 +01001316 ALOGV("... address = %s", address);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001317
1318 jint result = BOND_RESULT_SUCCESS;
1319 if (dbus_set_error_from_message(&err, msg)) {
1320 if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationFailed")) {
1321 // Pins did not match, or remote device did not respond to pin
1322 // request in time
Steve Block71f2cf12011-10-20 11:56:00 +01001323 ALOGV("... error = %s (%s)\n", err.name, err.message);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001324 result = BOND_RESULT_AUTH_FAILED;
1325 } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationRejected")) {
1326 // We rejected pairing, or the remote side rejected pairing. This
1327 // happens if either side presses 'cancel' at the pairing dialog.
Steve Block71f2cf12011-10-20 11:56:00 +01001328 ALOGV("... error = %s (%s)\n", err.name, err.message);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001329 result = BOND_RESULT_AUTH_REJECTED;
1330 } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationCanceled")) {
1331 // Not sure if this happens
Steve Block71f2cf12011-10-20 11:56:00 +01001332 ALOGV("... error = %s (%s)\n", err.name, err.message);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001333 result = BOND_RESULT_AUTH_CANCELED;
1334 } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.ConnectionAttemptFailed")) {
1335 // Other device is not responding at all
Steve Block71f2cf12011-10-20 11:56:00 +01001336 ALOGV("... error = %s (%s)\n", err.name, err.message);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001337 result = BOND_RESULT_REMOTE_DEVICE_DOWN;
1338 } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AlreadyExists")) {
1339 // already bonded
Steve Block71f2cf12011-10-20 11:56:00 +01001340 ALOGV("... error = %s (%s)\n", err.name, err.message);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001341 result = BOND_RESULT_SUCCESS;
1342 } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.InProgress") &&
1343 !strcmp(err.message, "Bonding in progress")) {
Steve Block71f2cf12011-10-20 11:56:00 +01001344 ALOGV("... error = %s (%s)\n", err.name, err.message);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001345 goto done;
1346 } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.InProgress") &&
1347 !strcmp(err.message, "Discover in progress")) {
Steve Block71f2cf12011-10-20 11:56:00 +01001348 ALOGV("... error = %s (%s)\n", err.name, err.message);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001349 result = BOND_RESULT_DISCOVERY_IN_PROGRESS;
Jaikumar Ganesh32d85712009-09-10 22:00:05 -07001350 } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.RepeatedAttempts")) {
Steve Block71f2cf12011-10-20 11:56:00 +01001351 ALOGV("... error = %s (%s)\n", err.name, err.message);
Jaikumar Ganesh32d85712009-09-10 22:00:05 -07001352 result = BOND_RESULT_REPEATED_ATTEMPTS;
1353 } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationTimeout")) {
Steve Block71f2cf12011-10-20 11:56:00 +01001354 ALOGV("... error = %s (%s)\n", err.name, err.message);
Jaikumar Ganesh32d85712009-09-10 22:00:05 -07001355 result = BOND_RESULT_AUTH_TIMEOUT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001356 } else {
1357 LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message);
1358 result = BOND_RESULT_ERROR;
1359 }
1360 }
1361
Jaikumar Ganesha7c0bdc2010-06-03 16:50:57 -07001362 addr = env->NewStringUTF(address);
Robert Greenwalt28d139f2009-04-02 22:41:08 -07001363 env->CallVoidMethod(nat->me,
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -07001364 method_onCreatePairedDeviceResult,
Jaikumar Ganesha7c0bdc2010-06-03 16:50:57 -07001365 addr,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001366 result);
Jaikumar Ganesha7c0bdc2010-06-03 16:50:57 -07001367 env->DeleteLocalRef(addr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001368done:
1369 dbus_error_free(&err);
1370 free(user);
1371}
1372
Jaikumar Ganesh1caa6d12009-09-18 11:32:54 -07001373void onCreateDeviceResult(DBusMessage *msg, void *user, void *n) {
Steve Block71f2cf12011-10-20 11:56:00 +01001374 ALOGV("%s", __FUNCTION__);
Jaikumar Ganesh1caa6d12009-09-18 11:32:54 -07001375
1376 native_data_t *nat = (native_data_t *)n;
1377 const char *address= (const char *)user;
1378 DBusError err;
1379 dbus_error_init(&err);
1380 JNIEnv *env;
1381 nat->vm->GetEnv((void**)&env, nat->envVer);
1382
Steve Block71f2cf12011-10-20 11:56:00 +01001383 ALOGV("... Address = %s", address);
Jaikumar Ganesh1caa6d12009-09-18 11:32:54 -07001384
Nick Pelly16fb88a2009-10-07 07:44:03 +02001385 jint result = CREATE_DEVICE_SUCCESS;
Jaikumar Ganesh1caa6d12009-09-18 11:32:54 -07001386 if (dbus_set_error_from_message(&err, msg)) {
Nick Pelly16fb88a2009-10-07 07:44:03 +02001387 if (dbus_error_has_name(&err, "org.bluez.Error.AlreadyExists")) {
1388 result = CREATE_DEVICE_ALREADY_EXISTS;
Jaikumar Ganeshcf5f6522010-02-17 17:19:26 -08001389 } else {
1390 result = CREATE_DEVICE_FAILED;
Nick Pelly16fb88a2009-10-07 07:44:03 +02001391 }
Jaikumar Ganesh1caa6d12009-09-18 11:32:54 -07001392 LOG_AND_FREE_DBUS_ERROR(&err);
Jaikumar Ganesh1caa6d12009-09-18 11:32:54 -07001393 }
Jaikumar Ganesha7c0bdc2010-06-03 16:50:57 -07001394 jstring addr = env->NewStringUTF(address);
Jaikumar Ganesh1caa6d12009-09-18 11:32:54 -07001395 env->CallVoidMethod(nat->me,
1396 method_onCreateDeviceResult,
Jaikumar Ganesha7c0bdc2010-06-03 16:50:57 -07001397 addr,
Jaikumar Ganesh1caa6d12009-09-18 11:32:54 -07001398 result);
Jaikumar Ganesha7c0bdc2010-06-03 16:50:57 -07001399 env->DeleteLocalRef(addr);
Jaikumar Ganesh1caa6d12009-09-18 11:32:54 -07001400 free(user);
1401}
1402
1403void onDiscoverServicesResult(DBusMessage *msg, void *user, void *n) {
Steve Block71f2cf12011-10-20 11:56:00 +01001404 ALOGV("%s", __FUNCTION__);
Jaikumar Ganesh1caa6d12009-09-18 11:32:54 -07001405
1406 native_data_t *nat = (native_data_t *)n;
1407 const char *path = (const char *)user;
1408 DBusError err;
1409 dbus_error_init(&err);
1410 JNIEnv *env;
1411 nat->vm->GetEnv((void**)&env, nat->envVer);
1412
Steve Block71f2cf12011-10-20 11:56:00 +01001413 ALOGV("... Device Path = %s", path);
Jaikumar Ganesh1caa6d12009-09-18 11:32:54 -07001414
1415 bool result = JNI_TRUE;
1416 if (dbus_set_error_from_message(&err, msg)) {
1417 LOG_AND_FREE_DBUS_ERROR(&err);
1418 result = JNI_FALSE;
1419 }
Jaikumar Ganesha7c0bdc2010-06-03 16:50:57 -07001420 jstring jPath = env->NewStringUTF(path);
Jaikumar Ganesh1caa6d12009-09-18 11:32:54 -07001421 env->CallVoidMethod(nat->me,
1422 method_onDiscoverServicesResult,
Jaikumar Ganesha7c0bdc2010-06-03 16:50:57 -07001423 jPath,
Jaikumar Ganesh1caa6d12009-09-18 11:32:54 -07001424 result);
Jaikumar Ganesha7c0bdc2010-06-03 16:50:57 -07001425 env->DeleteLocalRef(jPath);
Jaikumar Ganesh1caa6d12009-09-18 11:32:54 -07001426 free(user);
1427}
1428
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -07001429void onGetDeviceServiceChannelResult(DBusMessage *msg, void *user, void *n) {
Steve Block71f2cf12011-10-20 11:56:00 +01001430 ALOGV("%s", __FUNCTION__);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001431
1432 const char *address = (const char *) user;
Robert Greenwalt28d139f2009-04-02 22:41:08 -07001433 native_data_t *nat = (native_data_t *) n;
1434
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001435 DBusError err;
1436 dbus_error_init(&err);
Robert Greenwalt28d139f2009-04-02 22:41:08 -07001437 JNIEnv *env;
1438 nat->vm->GetEnv((void**)&env, nat->envVer);
1439
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001440 jint channel = -2;
1441
Steve Block71f2cf12011-10-20 11:56:00 +01001442 ALOGV("... address = %s", address);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001443
1444 if (dbus_set_error_from_message(&err, msg) ||
1445 !dbus_message_get_args(msg, &err,
1446 DBUS_TYPE_INT32, &channel,
1447 DBUS_TYPE_INVALID)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001448 LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message);
1449 dbus_error_free(&err);
1450 }
1451
1452done:
Jaikumar Ganesha7c0bdc2010-06-03 16:50:57 -07001453 jstring addr = env->NewStringUTF(address);
Robert Greenwalt28d139f2009-04-02 22:41:08 -07001454 env->CallVoidMethod(nat->me,
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -07001455 method_onGetDeviceServiceChannelResult,
Jaikumar Ganesha7c0bdc2010-06-03 16:50:57 -07001456 addr,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001457 channel);
Jaikumar Ganesha7c0bdc2010-06-03 16:50:57 -07001458 env->DeleteLocalRef(addr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001459 free(user);
1460}
Jaikumar Ganeshde075032010-07-19 16:28:27 -07001461
1462void onInputDeviceConnectionResult(DBusMessage *msg, void *user, void *n) {
Steve Block71f2cf12011-10-20 11:56:00 +01001463 ALOGV("%s", __FUNCTION__);
Jaikumar Ganeshde075032010-07-19 16:28:27 -07001464
1465 native_data_t *nat = (native_data_t *)n;
1466 const char *path = (const char *)user;
1467 DBusError err;
1468 dbus_error_init(&err);
1469 JNIEnv *env;
1470 nat->vm->GetEnv((void**)&env, nat->envVer);
1471
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -08001472 jint result = INPUT_OPERATION_SUCCESS;
Jaikumar Ganeshde075032010-07-19 16:28:27 -07001473 if (dbus_set_error_from_message(&err, msg)) {
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -08001474 if (!strcmp(err.name, BLUEZ_ERROR_IFC ".ConnectionAttemptFailed")) {
1475 result = INPUT_CONNECT_FAILED_ATTEMPT_FAILED;
1476 } else if (!strcmp(err.name, BLUEZ_ERROR_IFC ".AlreadyConnected")) {
1477 result = INPUT_CONNECT_FAILED_ALREADY_CONNECTED;
1478 } else if (!strcmp(err.name, BLUEZ_ERROR_IFC ".Failed")) {
1479 // TODO():This is flaky, need to change Bluez to add new error codes
1480 if (!strcmp(err.message, "Transport endpoint is not connected")) {
1481 result = INPUT_DISCONNECT_FAILED_NOT_CONNECTED;
1482 } else {
1483 result = INPUT_OPERATION_GENERIC_FAILURE;
1484 }
1485 } else {
1486 result = INPUT_OPERATION_GENERIC_FAILURE;
1487 }
Jaikumar Ganeshde075032010-07-19 16:28:27 -07001488 LOG_AND_FREE_DBUS_ERROR(&err);
Jaikumar Ganeshde075032010-07-19 16:28:27 -07001489 }
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -08001490
Steve Block71f2cf12011-10-20 11:56:00 +01001491 ALOGV("... Device Path = %s, result = %d", path, result);
Jaikumar Ganeshde075032010-07-19 16:28:27 -07001492 jstring jPath = env->NewStringUTF(path);
1493 env->CallVoidMethod(nat->me,
1494 method_onInputDeviceConnectionResult,
1495 jPath,
1496 result);
1497 env->DeleteLocalRef(jPath);
1498 free(user);
1499}
1500
Danica Chang6fdd0c62010-08-11 14:54:43 -07001501void onPanDeviceConnectionResult(DBusMessage *msg, void *user, void *n) {
Steve Block71f2cf12011-10-20 11:56:00 +01001502 ALOGV("%s", __FUNCTION__);
Danica Chang6fdd0c62010-08-11 14:54:43 -07001503
1504 native_data_t *nat = (native_data_t *)n;
1505 const char *path = (const char *)user;
1506 DBusError err;
1507 dbus_error_init(&err);
1508 JNIEnv *env;
1509 nat->vm->GetEnv((void**)&env, nat->envVer);
1510
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -08001511 jint result = PAN_OPERATION_SUCCESS;
Danica Chang6fdd0c62010-08-11 14:54:43 -07001512 if (dbus_set_error_from_message(&err, msg)) {
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -08001513 if (!strcmp(err.name, BLUEZ_ERROR_IFC ".ConnectionAttemptFailed")) {
1514 result = PAN_CONNECT_FAILED_ATTEMPT_FAILED;
1515 } else if (!strcmp(err.name, BLUEZ_ERROR_IFC ".Failed")) {
1516 // TODO():This is flaky, need to change Bluez to add new error codes
1517 if (!strcmp(err.message, "Device already connected")) {
1518 result = PAN_CONNECT_FAILED_ALREADY_CONNECTED;
1519 } else if (!strcmp(err.message, "Device not connected")) {
1520 result = PAN_DISCONNECT_FAILED_NOT_CONNECTED;
1521 } else {
1522 result = PAN_OPERATION_GENERIC_FAILURE;
1523 }
1524 } else {
1525 result = PAN_OPERATION_GENERIC_FAILURE;
1526 }
Danica Chang6fdd0c62010-08-11 14:54:43 -07001527 LOG_AND_FREE_DBUS_ERROR(&err);
Danica Chang6fdd0c62010-08-11 14:54:43 -07001528 }
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -08001529
Steve Block71f2cf12011-10-20 11:56:00 +01001530 ALOGV("... Pan Device Path = %s, result = %d", path, result);
Danica Chang6fdd0c62010-08-11 14:54:43 -07001531 jstring jPath = env->NewStringUTF(path);
1532 env->CallVoidMethod(nat->me,
1533 method_onPanDeviceConnectionResult,
1534 jPath,
1535 result);
1536 env->DeleteLocalRef(jPath);
1537 free(user);
1538}
1539
Jaikumar Ganeshb5d2d452011-09-07 14:16:52 -07001540void onHealthDeviceConnectionResult(DBusMessage *msg, void *user, void *n) {
Steve Block71f2cf12011-10-20 11:56:00 +01001541 ALOGV("%s", __FUNCTION__);
Jaikumar Ganeshb5d2d452011-09-07 14:16:52 -07001542
1543 native_data_t *nat = (native_data_t *)n;
1544 DBusError err;
1545 dbus_error_init(&err);
1546 JNIEnv *env;
1547 nat->vm->GetEnv((void**)&env, nat->envVer);
1548
1549 jint result = HEALTH_OPERATION_SUCCESS;
1550 if (dbus_set_error_from_message(&err, msg)) {
1551 if (!strcmp(err.name, BLUEZ_ERROR_IFC ".InvalidArgs")) {
1552 result = HEALTH_OPERATION_INVALID_ARGS;
1553 } else if (!strcmp(err.name, BLUEZ_ERROR_IFC ".HealthError")) {
1554 result = HEALTH_OPERATION_ERROR;
1555 } else if (!strcmp(err.name, BLUEZ_ERROR_IFC ".NotFound")) {
1556 result = HEALTH_OPERATION_NOT_FOUND;
1557 } else if (!strcmp(err.name, BLUEZ_ERROR_IFC ".NotAllowed")) {
1558 result = HEALTH_OPERATION_NOT_ALLOWED;
1559 } else {
1560 result = HEALTH_OPERATION_GENERIC_FAILURE;
1561 }
1562 LOG_AND_FREE_DBUS_ERROR(&err);
1563 }
1564
Jaikumar Ganeshb5d2d452011-09-07 14:16:52 -07001565 jint code = *(int *) user;
Steve Block71f2cf12011-10-20 11:56:00 +01001566 ALOGV("... Health Device Code = %d, result = %d", code, result);
Jaikumar Ganeshb5d2d452011-09-07 14:16:52 -07001567 env->CallVoidMethod(nat->me,
1568 method_onHealthDeviceConnectionResult,
1569 code,
1570 result);
1571 free(user);
1572}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001573#endif
1574
1575static JNINativeMethod sMethods[] = {
1576 /* name, signature, funcPtr */
1577 {"classInitNative", "()V", (void *)classInitNative},
1578 {"initializeNativeDataNative", "()V", (void *)initializeNativeDataNative},
1579 {"cleanupNativeDataNative", "()V", (void *)cleanupNativeDataNative},
Robert Greenwalt28d139f2009-04-02 22:41:08 -07001580 {"startEventLoopNative", "()V", (void *)startEventLoopNative},
1581 {"stopEventLoopNative", "()V", (void *)stopEventLoopNative},
1582 {"isEventLoopRunningNative", "()Z", (void *)isEventLoopRunningNative}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001583};
1584
1585int register_android_server_BluetoothEventLoop(JNIEnv *env) {
1586 return AndroidRuntime::registerNativeMethods(env,
1587 "android/server/BluetoothEventLoop", sMethods, NELEM(sMethods));
1588}
1589
1590} /* namespace android */