Home | History | Annotate | Download | only in jni
      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 
     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 
     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         ALOGE("%s: write() failed: %s (%d)", __FUNCTION__, strerror(errno),
     73              errno);
     74         return -1;
     75     }
     76     if (ret != len) {
     77         ALOGE("%s: write() only wrote %d of %d bytes", __FUNCTION__, ret, len);
     78         return -1;
     79     }
     80     return 0;
     81 }
     82 
     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 
     99 static void mask_eighth_bit(char *line)
    100 {
    101    for (;;line++) {
    102      if (0 == *line) return;
    103      *line &= 0x7F;
    104    }
    105 }
    106 
    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 = TEMP_FAILURE_RETRY(poll(&pfd, 1, timeout_ms));
    119     if (ret < 0) {
    120         ALOGE("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         ALOGW("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 = TEMP_FAILURE_RETRY(read(fd, bufit, 1));
    140 
    141         if (!rc)
    142             break;
    143 
    144         if (rc < 0) {
    145             if (errno == EBUSY) {
    146                 ALOGI("read() error %s (%d): repeating read()...",
    147                      strerror(errno), errno);
    148                 goto again;
    149             }
    150             *err = errno;
    151             ALOGE("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 = 0;
    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 
    182 static void classInitNative(JNIEnv* env, jclass clazz) {
    183     ALOGV("%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 
    192 static void initializeNativeDataNative(JNIEnv* env, jobject object,
    193                                        jint socketFd) {
    194     ALOGV("%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         ALOGE("%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         ALOGI("%s: ALREADY CONNECTED!", __FUNCTION__);
    212 #endif
    213 }
    214 
    215 static void cleanupNativeDataNative(JNIEnv* env, jobject object) {
    216     ALOGV("%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 
    227 static jboolean connectNative(JNIEnv *env, jobject obj)
    228 {
    229     ALOGV("%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         ALOGE("%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         ALOGE("%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             ALOGE("%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 
    280 static jint connectAsyncNative(JNIEnv *env, jobject obj) {
    281     ALOGV("%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         ALOGV("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             ALOGE("%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             ALOGE("%s: Can't set RFCOMM link mode", __FUNCTION__);
    310             close(nat->rfcomm_sock);
    311             return -1;
    312         }
    313         ALOGI("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                 ALOGI("async connect successful");
    334                 return 0;
    335             }
    336             else if (rc < 0) {
    337                 if (errno == EINPROGRESS || errno == EAGAIN)
    338                 {
    339                     ALOGI("async connect is in progress (%s)",
    340                          strerror(errno));
    341                     nat->rfcomm_connected = -1;
    342                     return 0;
    343                 }
    344                 else
    345                 {
    346                     ALOGE("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 
    358 static jint waitForAsyncConnectNative(JNIEnv *env, jobject obj,
    359                                            jint timeout_ms) {
    360     ALOGV("%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         ALOGI("RFCOMM is already connected!");
    369         return 1;
    370     }
    371 
    372     if (nat->rfcomm_sock >= 0 && nat->rfcomm_connected == 0) {
    373         ALOGI("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         ALOGI("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             ALOGV("Remaining time %ldms", (long)remaining);
    407             env->SetIntField(obj, field_mTimeoutRemainingMs,
    408                              remaining);
    409         }
    410 
    411         if (n <= 0) {
    412             if (n < 0)  {
    413                 ALOGE("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         ALOGV("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 = TEMP_FAILURE_RETRY(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                     ALOGE("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             ALOGI("Successful RFCOMM socket connect.");
    455             nat->rfcomm_connected = 1;
    456             return 1;
    457         }
    458     }
    459     else ALOGE("RFCOMM socket file descriptor %d is bad!",
    460               nat->rfcomm_sock);
    461 #endif
    462     return -1;
    463 }
    464 
    465 static void disconnectNative(JNIEnv *env, jobject obj) {
    466     ALOGV("%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 
    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_ALOGV() ALOG(LOG_VERBOSE, "Bluetooth AT sent", "%s", buf);
    498 
    499     free(buf);
    500 }
    501 
    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 
    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 
    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 
    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