Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright (C) 2010 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 #include <semaphore.h>
     18 #include <errno.h>
     19 
     20 #include "com_android_nfc.h"
     21 
     22 namespace android {
     23 
     24 /*
     25  * Callbacks
     26  */
     27 
     28 static void nfc_jni_disconnect_callback(void*        pContext,
     29                                                NFCSTATUS    status)
     30 {
     31    struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
     32    LOG_CALLBACK("nfc_jni_disconnect_callback", status);
     33 
     34    /* Report the callback status and wake up the caller */
     35    pCallbackData->status = status;
     36    sem_post(&pCallbackData->sem);
     37 }
     38 
     39 
     40 static void nfc_jni_connect_callback(void* pContext, uint8_t nErrCode, NFCSTATUS status)
     41 {
     42    struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
     43    LOG_CALLBACK("nfc_jni_llcp_connect_callback", status);
     44 
     45    if(status == NFCSTATUS_SUCCESS)
     46    {
     47       TRACE("Socket connected\n");
     48    }
     49    else
     50    {
     51       LOGD("Socket not connected:");
     52       switch(nErrCode)
     53       {
     54          case PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_ACTIVE:
     55             {
     56                LOGD("> SAP NOT ACTIVE\n");
     57             }break;
     58 
     59          case PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_FOUND:
     60             {
     61                LOGD("> SAP NOT FOUND\n");
     62             }break;
     63 
     64          case PHFRINFC_LLCP_DM_OPCODE_CONNECT_REJECTED:
     65             {
     66                LOGD("> CONNECT REJECTED\n");
     67             }break;
     68 
     69          case PHFRINFC_LLCP_DM_OPCODE_CONNECT_NOT_ACCEPTED:
     70             {
     71                LOGD("> CONNECT NOT ACCEPTED\n");
     72             }break;
     73 
     74          case PHFRINFC_LLCP_DM_OPCODE_SOCKET_NOT_AVAILABLE:
     75             {
     76                LOGD("> SOCKET NOT AVAILABLE\n");
     77             }break;
     78       }
     79    }
     80 
     81    /* Report the callback status and wake up the caller */
     82    pCallbackData->status = status;
     83    sem_post(&pCallbackData->sem);
     84 }
     85 
     86 
     87 
     88 
     89 static void nfc_jni_receive_callback(void* pContext, NFCSTATUS    status)
     90 {
     91    struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
     92    LOG_CALLBACK("nfc_jni_llcp_receive_callback", status);
     93 
     94    /* Report the callback status and wake up the caller */
     95    pCallbackData->status = status;
     96    sem_post(&pCallbackData->sem);
     97 }
     98 
     99 static void nfc_jni_send_callback(void *pContext, NFCSTATUS status)
    100 {
    101    struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
    102    LOG_CALLBACK("nfc_jni_llcp_send_callback", status);
    103 
    104    /* Report the callback status and wake up the caller */
    105    pCallbackData->status = status;
    106    sem_post(&pCallbackData->sem);
    107 }
    108 
    109 /*
    110  * Methods
    111  */
    112 static jboolean com_android_nfc_NativeLlcpSocket_doConnect(JNIEnv *e, jobject o, jint nSap)
    113 {
    114    NFCSTATUS ret;
    115    struct timespec ts;
    116    phLibNfc_Handle hRemoteDevice;
    117    phLibNfc_Handle hLlcpSocket;
    118    struct nfc_jni_callback_data cb_data;
    119    jboolean result = JNI_FALSE;
    120 
    121    /* Retrieve handles */
    122    hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o);
    123    hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
    124 
    125    /* Create the local semaphore */
    126    if (!nfc_cb_data_init(&cb_data, NULL))
    127    {
    128       goto clean_and_return;
    129    }
    130 
    131    TRACE("phLibNfc_Llcp_Connect(%d)",nSap);
    132    REENTRANCE_LOCK();
    133    ret = phLibNfc_Llcp_Connect(hRemoteDevice,
    134                                hLlcpSocket,
    135                                nSap,
    136                                nfc_jni_connect_callback,
    137                                (void*)&cb_data);
    138    REENTRANCE_UNLOCK();
    139    if(ret != NFCSTATUS_PENDING)
    140    {
    141       LOGE("phLibNfc_Llcp_Connect(%d) returned 0x%04x[%s]", nSap, ret, nfc_jni_get_status_name(ret));
    142       goto clean_and_return;
    143    }
    144    TRACE("phLibNfc_Llcp_Connect(%d) returned 0x%04x[%s]", nSap, ret, nfc_jni_get_status_name(ret));
    145 
    146    /* Wait for callback response */
    147    if(sem_wait(&cb_data.sem))
    148    {
    149       LOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
    150       goto clean_and_return;
    151    }
    152 
    153    if(cb_data.status != NFCSTATUS_SUCCESS)
    154    {
    155       LOGW("LLCP Connect request failed");
    156       goto clean_and_return;
    157    }
    158 
    159    result = JNI_TRUE;
    160 
    161 clean_and_return:
    162    nfc_cb_data_deinit(&cb_data);
    163    return result;
    164 }
    165 
    166 static jboolean com_android_nfc_NativeLlcpSocket_doConnectBy(JNIEnv *e, jobject o, jstring sn)
    167 {
    168    NFCSTATUS ret;
    169    struct timespec ts;
    170    phNfc_sData_t serviceName;
    171    phLibNfc_Handle hRemoteDevice;
    172    phLibNfc_Handle hLlcpSocket;
    173    struct nfc_jni_callback_data cb_data;
    174    jboolean result = JNI_FALSE;
    175 
    176    /* Retrieve handles */
    177    hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o);
    178    hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
    179 
    180    /* Create the local semaphore */
    181    if (!nfc_cb_data_init(&cb_data, NULL))
    182    {
    183       goto clean_and_return;
    184    }
    185 
    186    /* Service socket */
    187    serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL);
    188    serviceName.length = (uint32_t)e->GetStringUTFLength(sn);
    189 
    190    TRACE("phLibNfc_Llcp_ConnectByUri()");
    191    REENTRANCE_LOCK();
    192    ret = phLibNfc_Llcp_ConnectByUri(hRemoteDevice,
    193                                     hLlcpSocket,
    194                                     &serviceName,
    195                                     nfc_jni_connect_callback,
    196                                     (void*)&cb_data);
    197    REENTRANCE_UNLOCK();
    198    if(ret != NFCSTATUS_PENDING)
    199    {
    200       LOGE("phLibNfc_Llcp_ConnectByUri() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
    201       goto clean_and_return;
    202    }
    203    TRACE("phLibNfc_Llcp_ConnectByUri() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
    204 
    205    /* Wait for callback response */
    206    if(sem_wait(&cb_data.sem))
    207    {
    208       LOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
    209       goto clean_and_return;
    210    }
    211 
    212    if(cb_data.status != NFCSTATUS_SUCCESS)
    213    {
    214       goto clean_and_return;
    215    }
    216 
    217    result = JNI_TRUE;
    218 
    219 clean_and_return:
    220    nfc_cb_data_deinit(&cb_data);
    221    return result;
    222 }
    223 
    224 static jboolean com_android_nfc_NativeLlcpSocket_doClose(JNIEnv *e, jobject o)
    225 {
    226    NFCSTATUS ret;
    227    phLibNfc_Handle hLlcpSocket;
    228 
    229    /* Retrieve socket handle */
    230    hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
    231 
    232    TRACE("phLibNfc_Llcp_Close()");
    233    REENTRANCE_LOCK();
    234    ret = phLibNfc_Llcp_Close(hLlcpSocket);
    235    REENTRANCE_UNLOCK();
    236    if(ret != NFCSTATUS_SUCCESS)
    237    {
    238       LOGE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
    239       return FALSE;
    240    }
    241    TRACE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
    242    return TRUE;
    243 }
    244 
    245 static jboolean com_android_nfc_NativeLlcpSocket_doSend(JNIEnv *e, jobject o, jbyteArray  data)
    246 {
    247    NFCSTATUS ret;
    248    struct timespec ts;
    249    phLibNfc_Handle hRemoteDevice;
    250    phLibNfc_Handle hLlcpSocket;
    251    phNfc_sData_t sSendBuffer = {NULL, 0};
    252    struct nfc_jni_callback_data cb_data;
    253    jboolean result = JNI_FALSE;
    254 
    255    /* Retrieve handles */
    256    hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o);
    257    hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
    258 
    259    /* Create the local semaphore */
    260    if (!nfc_cb_data_init(&cb_data, NULL))
    261    {
    262       goto clean_and_return;
    263    }
    264 
    265    sSendBuffer.buffer = (uint8_t*)e->GetByteArrayElements(data, NULL);
    266    sSendBuffer.length = (uint32_t)e->GetArrayLength(data);
    267 
    268    TRACE("phLibNfc_Llcp_Send()");
    269    REENTRANCE_LOCK();
    270    ret = phLibNfc_Llcp_Send(hRemoteDevice,
    271                             hLlcpSocket,
    272                             &sSendBuffer,
    273                             nfc_jni_send_callback,
    274                             (void*)&cb_data);
    275    REENTRANCE_UNLOCK();
    276    if(ret != NFCSTATUS_PENDING)
    277    {
    278       LOGE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
    279       goto clean_and_return;
    280    }
    281    TRACE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
    282 
    283    /* Wait for callback response */
    284    if(sem_wait(&cb_data.sem))
    285    {
    286       LOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
    287       goto clean_and_return;
    288    }
    289 
    290    if(cb_data.status != NFCSTATUS_SUCCESS)
    291    {
    292        goto clean_and_return;
    293    }
    294 
    295    result = JNI_TRUE;
    296 
    297 clean_and_return:
    298    if (sSendBuffer.buffer != NULL)
    299    {
    300       e->ReleaseByteArrayElements(data, (jbyte*)sSendBuffer.buffer, JNI_ABORT);
    301    }
    302    nfc_cb_data_deinit(&cb_data);
    303    return result;
    304 }
    305 
    306 static jint com_android_nfc_NativeLlcpSocket_doReceive(JNIEnv *e, jobject o, jbyteArray  buffer)
    307 {
    308    NFCSTATUS ret;
    309    struct timespec ts;
    310    phLibNfc_Handle hRemoteDevice;
    311    phLibNfc_Handle hLlcpSocket;
    312    phNfc_sData_t sReceiveBuffer = {NULL, 0};
    313    struct nfc_jni_callback_data cb_data;
    314    jint result = 0;
    315 
    316    /* Retrieve handles */
    317    hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o);
    318    hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
    319 
    320    /* Create the local semaphore */
    321    if (!nfc_cb_data_init(&cb_data, NULL))
    322    {
    323       goto clean_and_return;
    324    }
    325 
    326    sReceiveBuffer.buffer = (uint8_t*)e->GetByteArrayElements(buffer, NULL);
    327    sReceiveBuffer.length = (uint32_t)e->GetArrayLength(buffer);
    328 
    329    TRACE("phLibNfc_Llcp_Recv()");
    330    REENTRANCE_LOCK();
    331    ret = phLibNfc_Llcp_Recv(hRemoteDevice,
    332                             hLlcpSocket,
    333                             &sReceiveBuffer,
    334                             nfc_jni_receive_callback,
    335                             (void*)&cb_data);
    336    REENTRANCE_UNLOCK();
    337    if(ret == NFCSTATUS_PENDING)
    338    {
    339       /* Wait for callback response */
    340       if(sem_wait(&cb_data.sem))
    341       {
    342          LOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
    343          goto clean_and_return;
    344       }
    345 
    346       if(cb_data.status == NFCSTATUS_SUCCESS)
    347       {
    348          result = sReceiveBuffer.length;
    349       }
    350    }
    351    else if (ret == NFCSTATUS_SUCCESS)
    352    {
    353       result = sReceiveBuffer.length;
    354    }
    355    else
    356    {
    357       /* Return status should be either SUCCESS or PENDING */
    358       LOGE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
    359       goto clean_and_return;
    360    }
    361    TRACE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
    362 
    363 clean_and_return:
    364    if (sReceiveBuffer.buffer != NULL)
    365    {
    366       e->ReleaseByteArrayElements(buffer, (jbyte*)sReceiveBuffer.buffer, 0);
    367    }
    368    nfc_cb_data_deinit(&cb_data);
    369    return result;
    370 }
    371 
    372 static jint com_android_nfc_NativeLlcpSocket_doGetRemoteSocketMIU(JNIEnv *e, jobject o)
    373 {
    374    NFCSTATUS ret;
    375    phLibNfc_Handle hRemoteDevice;
    376    phLibNfc_Handle hLlcpSocket;
    377    phLibNfc_Llcp_sSocketOptions_t   remoteSocketOption;
    378 
    379    /* Retrieve handles */
    380    hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o);
    381    hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
    382 
    383    TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(MIU)");
    384    REENTRANCE_LOCK();
    385    ret  = phLibNfc_Llcp_SocketGetRemoteOptions(hRemoteDevice,
    386                                                hLlcpSocket,
    387                                                &remoteSocketOption);
    388    REENTRANCE_UNLOCK();
    389    if(ret == NFCSTATUS_SUCCESS)
    390    {
    391       TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(MIU) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
    392       return remoteSocketOption.miu;
    393    }
    394    else
    395    {
    396       LOGW("phLibNfc_Llcp_SocketGetRemoteOptions(MIU) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
    397       return 0;
    398    }
    399 }
    400 
    401 static jint com_android_nfc_NativeLlcpSocket_doGetRemoteSocketRW(JNIEnv *e, jobject o)
    402 {
    403    NFCSTATUS ret;
    404    phLibNfc_Handle hRemoteDevice;
    405    phLibNfc_Handle hLlcpSocket;
    406    phLibNfc_Llcp_sSocketOptions_t   remoteSocketOption;
    407 
    408    /* Retrieve handles */
    409    hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o);
    410    hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
    411 
    412    TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(RW)");
    413    REENTRANCE_LOCK();
    414    ret  = phLibNfc_Llcp_SocketGetRemoteOptions(hRemoteDevice,
    415                                                hLlcpSocket,
    416                                                &remoteSocketOption);
    417    REENTRANCE_UNLOCK();
    418    if(ret == NFCSTATUS_SUCCESS)
    419    {
    420       TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(RW) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
    421       return remoteSocketOption.rw;
    422    }
    423    else
    424    {
    425       LOGW("phLibNfc_Llcp_SocketGetRemoteOptions(RW) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
    426       return 0;
    427    }
    428 }
    429 
    430 
    431 /*
    432  * JNI registration.
    433  */
    434 static JNINativeMethod gMethods[] =
    435 {
    436    {"doConnect", "(I)Z",
    437       (void *)com_android_nfc_NativeLlcpSocket_doConnect},
    438 
    439    {"doConnectBy", "(Ljava/lang/String;)Z",
    440       (void *)com_android_nfc_NativeLlcpSocket_doConnectBy},
    441 
    442    {"doClose", "()Z",
    443       (void *)com_android_nfc_NativeLlcpSocket_doClose},
    444 
    445    {"doSend", "([B)Z",
    446       (void *)com_android_nfc_NativeLlcpSocket_doSend},
    447 
    448    {"doReceive", "([B)I",
    449       (void *)com_android_nfc_NativeLlcpSocket_doReceive},
    450 
    451    {"doGetRemoteSocketMiu", "()I",
    452       (void *)com_android_nfc_NativeLlcpSocket_doGetRemoteSocketMIU},
    453 
    454    {"doGetRemoteSocketRw", "()I",
    455       (void *)com_android_nfc_NativeLlcpSocket_doGetRemoteSocketRW},
    456 };
    457 
    458 
    459 int register_com_android_nfc_NativeLlcpSocket(JNIEnv *e)
    460 {
    461    return jniRegisterNativeMethods(e,
    462       "com/android/nfc/NativeLlcpSocket",gMethods, NELEM(gMethods));
    463 }
    464 
    465 } // namespace android
    466