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