blob: bb19e92b15f80c03b60ea3ebb527dfc4e830eb94 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2** Copyright 2006, 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 "BT HSHFP"
18
19#include "android_bluetooth_common.h"
20#include "android_runtime/AndroidRuntime.h"
21#include "JNIHelp.h"
22#include "jni.h"
23#include "utils/Log.h"
24#include "utils/misc.h"
25
26#include <stdio.h>
27#include <string.h>
28#include <stdlib.h>
29#include <errno.h>
30#include <unistd.h>
31#include <fcntl.h>
32#include <sys/socket.h>
33#include <sys/uio.h>
34#include <sys/poll.h>
35
36#ifdef HAVE_BLUETOOTH
37#include <bluetooth/bluetooth.h>
38#include <bluetooth/rfcomm.h>
39#include <bluetooth/sco.h>
40#endif
41
42namespace android {
43
44#ifdef HAVE_BLUETOOTH
45static jfieldID field_mNativeData;
46static jfieldID field_mAddress;
47static jfieldID field_mRfcommChannel;
48static jfieldID field_mTimeoutRemainingMs;
49
50typedef struct {
51 jstring address;
52 const char *c_address;
53 int rfcomm_channel;
54 int last_read_err;
55 int rfcomm_sock;
56 int rfcomm_connected; // -1 in progress, 0 not connected, 1 connected
57 int rfcomm_sock_flags;
58} native_data_t;
59
60static inline native_data_t * get_native_data(JNIEnv *env, jobject object) {
61 return (native_data_t *)(env->GetIntField(object, field_mNativeData));
62}
63
64static const char CRLF[] = "\xd\xa";
65static const int CRLF_LEN = 2;
66
67static inline int write_error_check(int fd, const char* line, int len) {
68 int ret;
69 errno = 0;
70 ret = write(fd, line, len);
71 if (ret < 0) {
72 LOGE("%s: write() failed: %s (%d)", __FUNCTION__, strerror(errno),
73 errno);
74 return -1;
75 }
76 if (ret != len) {
77 LOGE("%s: write() only wrote %d of %d bytes", __FUNCTION__, ret, len);
78 return -1;
79 }
80 return 0;
81}
82
83static int send_line(int fd, const char* line) {
84 int nw;
85 int len = strlen(line);
86 int llen = len + CRLF_LEN * 2 + 1;
87 char *buffer = (char *)calloc(llen, sizeof(char));
88
89 snprintf(buffer, llen, "%s%s%s", CRLF, line, CRLF);
90
91 if (write_error_check(fd, buffer, llen - 1)) {
92 free(buffer);
93 return -1;
94 }
95 free(buffer);
96 return 0;
97}
98
99static const char* get_line(int fd, char *buf, int len, int timeout_ms,
100 int *err) {
101 char *bufit=buf;
102 int fd_flags = fcntl(fd, F_GETFL, 0);
103 struct pollfd pfd;
104
105again:
106 *bufit = 0;
107 pfd.fd = fd;
108 pfd.events = POLLIN;
109 *err = errno = 0;
110 int ret = poll(&pfd, 1, timeout_ms);
111 if (ret < 0) {
112 LOGE("poll() error\n");
113 *err = errno;
114 return NULL;
115 }
116 if (ret == 0) {
117 return NULL;
118 }
119
120 if (pfd.revents & (POLLHUP | POLLERR | POLLNVAL)) {
121 LOGW("RFCOMM poll() returned success (%d), "
122 "but with an unexpected revents bitmask: %#x\n", ret, pfd.revents);
123 errno = EIO;
124 *err = errno;
125 return NULL;
126 }
127
128 while ((int)(bufit - buf) < len)
129 {
130 errno = 0;
131 int rc = read(fd, bufit, 1);
132
133 if (!rc)
134 break;
135
136 if (rc < 0) {
137 if (errno == EBUSY) {
138 LOGI("read() error %s (%d): repeating read()...",
139 strerror(errno), errno);
140 goto again;
141 }
142 *err = errno;
143 LOGE("read() error %s (%d)", strerror(errno), errno);
144 return NULL;
145 }
146
147
148 if (*bufit=='\xd') {
149 break;
150 }
151
152 if (*bufit=='\xa')
153 bufit = buf;
154 else
155 bufit++;
156 }
157
158 *bufit = '\x0';
159 LOG(LOG_INFO, "Bluetooth AT recv", buf);
160
161 return buf;
162}
163#endif
164
165static void classInitNative(JNIEnv* env, jclass clazz) {
166 LOGV(__FUNCTION__);
167#ifdef HAVE_BLUETOOTH
168 field_mNativeData = get_field(env, clazz, "mNativeData", "I");
169 field_mAddress = get_field(env, clazz, "mAddress", "Ljava/lang/String;");
170 field_mTimeoutRemainingMs = get_field(env, clazz, "mTimeoutRemainingMs", "I");
171 field_mRfcommChannel = get_field(env, clazz, "mRfcommChannel", "I");
172#endif
173}
174
175static void initializeNativeDataNative(JNIEnv* env, jobject object,
176 jint socketFd) {
177 LOGV(__FUNCTION__);
178#ifdef HAVE_BLUETOOTH
179 native_data_t *nat = (native_data_t *)calloc(1, sizeof(native_data_t));
180 if (NULL == nat) {
181 LOGE("%s: out of memory!", __FUNCTION__);
182 return;
183 }
184
185 env->SetIntField(object, field_mNativeData, (jint)nat);
186 nat->address =
187 (jstring)env->NewGlobalRef(env->GetObjectField(object,
188 field_mAddress));
189 nat->c_address = env->GetStringUTFChars(nat->address, NULL);
190 nat->rfcomm_channel = env->GetIntField(object, field_mRfcommChannel);
191 nat->rfcomm_sock = socketFd;
192 nat->rfcomm_connected = socketFd >= 0;
193 if (nat->rfcomm_connected)
194 LOGI("%s: ALREADY CONNECTED!", __FUNCTION__);
195#endif
196}
197
198static void cleanupNativeDataNative(JNIEnv* env, jobject object) {
199 LOGV(__FUNCTION__);
200#ifdef HAVE_BLUETOOTH
201 native_data_t *nat =
202 (native_data_t *)env->GetIntField(object, field_mNativeData);
203 env->ReleaseStringUTFChars(nat->address, nat->c_address);
204 env->DeleteGlobalRef(nat->address);
205 if (nat)
206 free(nat);
207#endif
208}
209
210static jboolean connectNative(JNIEnv *env, jobject obj)
211{
212 LOGV(__FUNCTION__);
213#ifdef HAVE_BLUETOOTH
214 int lm;
215 struct sockaddr_rc addr;
216 native_data_t *nat = get_native_data(env, obj);
217
218 nat->rfcomm_sock = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
219
220 if (nat->rfcomm_sock < 0) {
221 LOGE("%s: Could not create RFCOMM socket: %s\n", __FUNCTION__,
222 strerror(errno));
223 return JNI_FALSE;
224 }
225
226 if (debug_no_encrypt()) {
227 lm = RFCOMM_LM_AUTH;
228 } else {
229 lm = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT;
230 }
231
232 if (lm && setsockopt(nat->rfcomm_sock, SOL_RFCOMM, RFCOMM_LM, &lm,
233 sizeof(lm)) < 0) {
234 LOGE("%s: Can't set RFCOMM link mode", __FUNCTION__);
235 close(nat->rfcomm_sock);
236 return JNI_FALSE;
237 }
238
239 memset(&addr, 0, sizeof(struct sockaddr_rc));
240 get_bdaddr(nat->c_address, &addr.rc_bdaddr);
241 addr.rc_channel = nat->rfcomm_channel;
242 addr.rc_family = AF_BLUETOOTH;
243 nat->rfcomm_connected = 0;
244 while (nat->rfcomm_connected == 0) {
245 if (connect(nat->rfcomm_sock, (struct sockaddr *)&addr,
246 sizeof(addr)) < 0) {
247 if (errno == EINTR) continue;
248 LOGE("%s: connect() failed: %s\n", __FUNCTION__, strerror(errno));
249 close(nat->rfcomm_sock);
250 nat->rfcomm_sock = -1;
251 return JNI_FALSE;
252 } else {
253 nat->rfcomm_connected = 1;
254 }
255 }
256
257 return JNI_TRUE;
258#else
259 return JNI_FALSE;
260#endif
261}
262
263static jboolean connectAsyncNative(JNIEnv *env, jobject obj) {
264 LOGV(__FUNCTION__);
265#ifdef HAVE_BLUETOOTH
266 struct sockaddr_rc addr;
267 native_data_t *nat = get_native_data(env, obj);
268
269 if (nat->rfcomm_connected) {
270 LOGV("RFCOMM socket is already connected or connection is in progress.");
271 return JNI_TRUE;
272 }
273
274 if (nat->rfcomm_sock < 0) {
275 int lm;
276
277 nat->rfcomm_sock = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
278 if (nat->rfcomm_sock < 0) {
279 LOGE("%s: Could not create RFCOMM socket: %s\n", __FUNCTION__,
280 strerror(errno));
281 return JNI_FALSE;
282 }
283
284 if (debug_no_encrypt()) {
285 lm = RFCOMM_LM_AUTH;
286 } else {
287 lm = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT;
288 }
289
290 if (lm && setsockopt(nat->rfcomm_sock, SOL_RFCOMM, RFCOMM_LM, &lm,
291 sizeof(lm)) < 0) {
292 LOGE("%s: Can't set RFCOMM link mode", __FUNCTION__);
293 close(nat->rfcomm_sock);
294 return JNI_FALSE;
295 }
296 LOGI("Created RFCOMM socket fd %d.", nat->rfcomm_sock);
297 }
298
299 memset(&addr, 0, sizeof(struct sockaddr_rc));
300 get_bdaddr(nat->c_address, &addr.rc_bdaddr);
301 addr.rc_channel = nat->rfcomm_channel;
302 addr.rc_family = AF_BLUETOOTH;
303 if (nat->rfcomm_sock_flags >= 0) {
304 nat->rfcomm_sock_flags = fcntl(nat->rfcomm_sock, F_GETFL, 0);
305 if (fcntl(nat->rfcomm_sock,
306 F_SETFL, nat->rfcomm_sock_flags | O_NONBLOCK) >= 0) {
307 int rc;
308 nat->rfcomm_connected = 0;
309 errno = 0;
310 rc = connect(nat->rfcomm_sock,
311 (struct sockaddr *)&addr,
312 sizeof(addr));
313
314 if (rc >= 0) {
315 nat->rfcomm_connected = 1;
316 LOGI("async connect successful");
317 return JNI_TRUE;
318 }
319 else if (rc < 0) {
320 if (errno == EINPROGRESS || errno == EAGAIN)
321 {
322 LOGI("async connect is in progress (%s)",
323 strerror(errno));
324 nat->rfcomm_connected = -1;
325 return JNI_TRUE;
326 }
327 else
328 {
329 LOGE("async connect error: %s (%d)", strerror(errno), errno);
330 close(nat->rfcomm_sock);
331 nat->rfcomm_sock = -1;
332 return JNI_FALSE;
333 }
334 }
335 } // fcntl(nat->rfcomm_sock ...)
336 } // if (nat->rfcomm_sock_flags >= 0)
337#endif
338 return JNI_FALSE;
339}
340
341static jint waitForAsyncConnectNative(JNIEnv *env, jobject obj,
342 jint timeout_ms) {
343 LOGV(__FUNCTION__);
344#ifdef HAVE_BLUETOOTH
345 struct sockaddr_rc addr;
346 native_data_t *nat = get_native_data(env, obj);
347
348 env->SetIntField(obj, field_mTimeoutRemainingMs, timeout_ms);
349
350 if (nat->rfcomm_connected > 0) {
351 LOGI("RFCOMM is already connected!");
352 return 1;
353 }
354
355 if (nat->rfcomm_sock >= 0 && nat->rfcomm_connected == 0) {
356 LOGI("Re-opening RFCOMM socket.");
357 close(nat->rfcomm_sock);
358 nat->rfcomm_sock = -1;
359 }
360 if (JNI_FALSE == connectAsyncNative(env, obj)) {
361 LOGI("Failed to re-open RFCOMM socket!");
362 return -1;
363 }
364
365 if (nat->rfcomm_sock >= 0) {
366 /* Do an asynchronous select() */
367 int n;
368 fd_set rset, wset;
369 struct timeval to;
370
371 FD_ZERO(&rset);
372 FD_ZERO(&wset);
373 FD_SET(nat->rfcomm_sock, &rset);
374 FD_SET(nat->rfcomm_sock, &wset);
375 if (timeout_ms >= 0) {
376 to.tv_sec = timeout_ms / 1000;
377 to.tv_usec = 1000 * (timeout_ms % 1000);
378 }
379 n = select(nat->rfcomm_sock + 1,
380 &rset,
381 &wset,
382 NULL,
383 (timeout_ms < 0 ? NULL : &to));
384
385 if (timeout_ms > 0) {
386 jint remaining = to.tv_sec*1000 + to.tv_usec/1000;
387 LOGV("Remaining time %ldms", (long)remaining);
388 env->SetIntField(obj, field_mTimeoutRemainingMs,
389 remaining);
390 }
391
392 if (n <= 0) {
393 if (n < 0) {
394 LOGE("select() on RFCOMM socket: %s (%d)",
395 strerror(errno),
396 errno);
397 return -1;
398 }
399 return 0;
400 }
401 /* n must be equal to 1 and either rset or wset must have the
402 file descriptor set. */
403 LOGV("select() returned %d.", n);
404 if (FD_ISSET(nat->rfcomm_sock, &rset) ||
405 FD_ISSET(nat->rfcomm_sock, &wset))
406 {
407 /* A trial async read() will tell us if everything is OK. */
408 {
409 char ch;
410 errno = 0;
411 int nr = read(nat->rfcomm_sock, &ch, 1);
412 /* It should be that nr != 1 because we just opened a socket
413 and we haven't sent anything over it for the other side to
414 respond... but one can't be paranoid enough.
415 */
416 if (nr >= 0 || errno != EAGAIN) {
417 LOGE("RFCOMM async connect() error: %s (%d), nr = %d\n",
418 strerror(errno),
419 errno,
420 nr);
421 /* Clear the rfcomm_connected flag to cause this function
422 to re-create the socket and re-attempt the connect()
423 the next time it is called.
424 */
425 nat->rfcomm_connected = 0;
426 /* Restore the blocking properties of the socket. */
427 fcntl(nat->rfcomm_sock, F_SETFL, nat->rfcomm_sock_flags);
428 close(nat->rfcomm_sock);
429 nat->rfcomm_sock = -1;
430 return -1;
431 }
432 }
433 /* Restore the blocking properties of the socket. */
434 fcntl(nat->rfcomm_sock, F_SETFL, nat->rfcomm_sock_flags);
435 LOGI("Successful RFCOMM socket connect.");
436 nat->rfcomm_connected = 1;
437 return 1;
438 }
439 }
440 else LOGE("RFCOMM socket file descriptor %d is bad!",
441 nat->rfcomm_sock);
442#endif
443 return -1;
444}
445
446static void disconnectNative(JNIEnv *env, jobject obj) {
447 LOGV(__FUNCTION__);
448#ifdef HAVE_BLUETOOTH
449 native_data_t *nat = get_native_data(env, obj);
450 if (nat->rfcomm_sock >= 0) {
451 close(nat->rfcomm_sock);
452 nat->rfcomm_sock = -1;
453 nat->rfcomm_connected = 0;
454 }
455#endif
456}
457
458static void pretty_log_urc(const char *urc) {
459 size_t i;
460 bool in_line_break = false;
461 char *buf = (char *)calloc(strlen(urc) + 1, sizeof(char));
462
463 strcpy(buf, urc);
464 for (i = 0; i < strlen(buf); i++) {
465 switch(buf[i]) {
466 case '\r':
467 case '\n':
468 in_line_break = true;
469 buf[i] = ' ';
470 break;
471 default:
472 if (in_line_break) {
473 in_line_break = false;
474 buf[i-1] = '\n';
475 }
476 }
477 }
478 LOG(LOG_INFO, "Bluetooth AT sent", buf);
479
480 free(buf);
481}
482
483static jboolean sendURCNative(JNIEnv *env, jobject obj, jstring urc) {
484#ifdef HAVE_BLUETOOTH
485 native_data_t *nat = get_native_data(env, obj);
486 if (nat->rfcomm_connected) {
487 const char *c_urc = env->GetStringUTFChars(urc, NULL);
488 jboolean ret = send_line(nat->rfcomm_sock, c_urc) == 0 ? JNI_TRUE : JNI_FALSE;
489 if (ret == JNI_TRUE) pretty_log_urc(c_urc);
490 env->ReleaseStringUTFChars(urc, c_urc);
491 return ret;
492 }
493#endif
494 return JNI_FALSE;
495}
496
497static jstring readNative(JNIEnv *env, jobject obj, jint timeout_ms) {
498#ifdef HAVE_BLUETOOTH
499 {
500 native_data_t *nat = get_native_data(env, obj);
501 if (nat->rfcomm_connected) {
502 char buf[128];
503 const char *ret = get_line(nat->rfcomm_sock,
504 buf, sizeof(buf),
505 timeout_ms,
506 &nat->last_read_err);
507 return ret ? env->NewStringUTF(ret) : NULL;
508 }
509 return NULL;
510 }
511#else
512 return NULL;
513#endif
514}
515
516static jint getLastReadStatusNative(JNIEnv *env, jobject obj) {
517#ifdef HAVE_BLUETOOTH
518 {
519 native_data_t *nat = get_native_data(env, obj);
520 if (nat->rfcomm_connected)
521 return (jint)nat->last_read_err;
522 return 0;
523 }
524#else
525 return 0;
526#endif
527}
528
529static JNINativeMethod sMethods[] = {
530 /* name, signature, funcPtr */
531 {"classInitNative", "()V", (void*)classInitNative},
532 {"initializeNativeDataNative", "(I)V", (void *)initializeNativeDataNative},
533 {"cleanupNativeDataNative", "()V", (void *)cleanupNativeDataNative},
534 {"connectNative", "()Z", (void *)connectNative},
535 {"connectAsyncNative", "()Z", (void *)connectAsyncNative},
536 {"waitForAsyncConnectNative", "(I)I", (void *)waitForAsyncConnectNative},
537 {"disconnectNative", "()V", (void *)disconnectNative},
538 {"sendURCNative", "(Ljava/lang/String;)Z", (void *)sendURCNative},
539 {"readNative", "(I)Ljava/lang/String;", (void *)readNative},
540 {"getLastReadStatusNative", "()I", (void *)getLastReadStatusNative},
541};
542
543int register_android_bluetooth_HeadsetBase(JNIEnv *env) {
544 return AndroidRuntime::registerNativeMethods(env,
545 "android/bluetooth/HeadsetBase", sMethods, NELEM(sMethods));
546}
547
548} /* namespace android */