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       ALOGD("Socket not connected:");
     52       switch(nErrCode)
     53       {
     54          case PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_ACTIVE:
     55             {
     56                ALOGD("> SAP NOT ACTIVE\n");
     57             }break;
     58 
     59          case PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_FOUND:
     60             {
     61                ALOGD("> SAP NOT FOUND\n");
     62             }break;
     63 
     64          case PHFRINFC_LLCP_DM_OPCODE_CONNECT_REJECTED:
     65             {
     66                ALOGD("> CONNECT REJECTED\n");
     67             }break;
     68 
     69          case PHFRINFC_LLCP_DM_OPCODE_CONNECT_NOT_ACCEPTED:
     70             {
     71                ALOGD("> CONNECT NOT ACCEPTED\n");
     72             }break;
     73 
     74          case PHFRINFC_LLCP_DM_OPCODE_SOCKET_NOT_AVAILABLE:
     75             {
     76                ALOGD("> 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       ALOGE("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       ALOGE("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       ALOGW("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 = {0};
    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       ALOGE("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       ALOGE("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    if (serviceName.buffer != NULL) {
    221       e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer);
    222    }
    223    nfc_cb_data_deinit(&cb_data);
    224    return result;
    225 }
    226 
    227 static jboolean com_android_nfc_NativeLlcpSocket_doClose(JNIEnv *e, jobject o)
    228 {
    229    NFCSTATUS ret;
    230    phLibNfc_Handle hLlcpSocket;
    231 
    232    /* Retrieve socket handle */
    233    hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
    234 
    235    TRACE("phLibNfc_Llcp_Close()");
    236    REENTRANCE_LOCK();
    237    ret = phLibNfc_Llcp_Close(hLlcpSocket);
    238    REENTRANCE_UNLOCK();
    239    if(ret != NFCSTATUS_SUCCESS)
    240    {
    241       ALOGE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
    242       return FALSE;
    243    }
    244    TRACE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
    245    return TRUE;
    246 }
    247 
    248 static jboolean com_android_nfc_NativeLlcpSocket_doSend(JNIEnv *e, jobject o, jbyteArray  data)
    249 {
    250    NFCSTATUS ret;
    251    struct timespec ts;
    252    phLibNfc_Handle hRemoteDevice;
    253    phLibNfc_Handle hLlcpSocket;
    254    phNfc_sData_t sSendBuffer = {NULL, 0};
    255    struct nfc_jni_callback_data cb_data;
    256    jboolean result = JNI_FALSE;
    257 
    258    /* Retrieve handles */
    259    hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o);
    260    hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
    261 
    262    /* Create the local semaphore */
    263    if (!nfc_cb_data_init(&cb_data, NULL))
    264    {
    265       goto clean_and_return;
    266    }
    267 
    268    sSendBuffer.buffer = (uint8_t*)e->GetByteArrayElements(data, NULL);
    269    sSendBuffer.length = (uint32_t)e->GetArrayLength(data);
    270 
    271    TRACE("phLibNfc_Llcp_Send()");
    272    REENTRANCE_LOCK();
    273    ret = phLibNfc_Llcp_Send(hRemoteDevice,
    274                             hLlcpSocket,
    275                             &sSendBuffer,
    276                             nfc_jni_send_callback,
    277                             (void*)&cb_data);
    278    REENTRANCE_UNLOCK();
    279    if(ret != NFCSTATUS_PENDING)
    280    {
    281       ALOGE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
    282       goto clean_and_return;
    283    }
    284    TRACE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
    285 
    286    /* Wait for callback response */
    287    if(sem_wait(&cb_data.sem))
    288    {
    289       ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
    290       goto clean_and_return;
    291    }
    292 
    293    if(cb_data.status != NFCSTATUS_SUCCESS)
    294    {
    295        goto clean_and_return;
    296    }
    297 
    298    result = JNI_TRUE;
    299 
    300 clean_and_return:
    301    if (sSendBuffer.buffer != NULL)
    302    {
    303       e->ReleaseByteArrayElements(data, (jbyte*)sSendBuffer.buffer, JNI_ABORT);
    304    }
    305    nfc_cb_data_deinit(&cb_data);
    306    return result;
    307 }
    308 
    309 static jint com_android_nfc_NativeLlcpSocket_doReceive(JNIEnv *e, jobject o, jbyteArray  buffer)
    310 {
    311    NFCSTATUS ret;
    312    struct timespec ts;
    313    phLibNfc_Handle hRemoteDevice;
    314    phLibNfc_Handle hLlcpSocket;
    315    phNfc_sData_t sReceiveBuffer = {NULL, 0};
    316    struct nfc_jni_callback_data cb_data;
    317    jint result = -1;
    318 
    319    /* Retrieve handles */
    320    hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o);
    321    hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
    322 
    323    /* Create the local semaphore */
    324    if (!nfc_cb_data_init(&cb_data, NULL))
    325    {
    326       goto clean_and_return;
    327    }
    328 
    329    sReceiveBuffer.buffer = (uint8_t*)e->GetByteArrayElements(buffer, NULL);
    330    sReceiveBuffer.length = (uint32_t)e->GetArrayLength(buffer);
    331 
    332    TRACE("phLibNfc_Llcp_Recv()");
    333    REENTRANCE_LOCK();
    334    ret = phLibNfc_Llcp_Recv(hRemoteDevice,
    335                             hLlcpSocket,
    336                             &sReceiveBuffer,
    337                             nfc_jni_receive_callback,
    338                             (void*)&cb_data);
    339    REENTRANCE_UNLOCK();
    340    if(ret == NFCSTATUS_PENDING)
    341    {
    342       /* Wait for callback response */
    343       if(sem_wait(&cb_data.sem))
    344       {
    345          ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
    346          goto clean_and_return;
    347       }
    348 
    349       if(cb_data.status == NFCSTATUS_SUCCESS)
    350       {
    351          result = sReceiveBuffer.length;
    352       }
    353    }
    354    else if (ret == NFCSTATUS_SUCCESS)
    355    {
    356       result = sReceiveBuffer.length;
    357    }
    358    else
    359    {
    360       /* Return status should be either SUCCESS or PENDING */
    361       ALOGE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
    362       goto clean_and_return;
    363    }
    364    TRACE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
    365 
    366 clean_and_return:
    367    if (sReceiveBuffer.buffer != NULL)
    368    {
    369       e->ReleaseByteArrayElements(buffer, (jbyte*)sReceiveBuffer.buffer, 0);
    370    }
    371    nfc_cb_data_deinit(&cb_data);
    372    return result;
    373 }
    374 
    375 static jint com_android_nfc_NativeLlcpSocket_doGetRemoteSocketMIU(JNIEnv *e, jobject o)
    376 {
    377    NFCSTATUS ret;
    378    phLibNfc_Handle hRemoteDevice;
    379    phLibNfc_Handle hLlcpSocket;
    380    phLibNfc_Llcp_sSocketOptions_t   remoteSocketOption;
    381 
    382    /* Retrieve handles */
    383    hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o);
    384    hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
    385 
    386    TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(MIU)");
    387    REENTRANCE_LOCK();
    388    ret  = phLibNfc_Llcp_SocketGetRemoteOptions(hRemoteDevice,
    389                                                hLlcpSocket,
    390                                                &remoteSocketOption);
    391    REENTRANCE_UNLOCK();
    392    if(ret == NFCSTATUS_SUCCESS)
    393    {
    394       TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(MIU) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
    395       return remoteSocketOption.miu;
    396    }
    397    else
    398    {
    399       ALOGW("phLibNfc_Llcp_SocketGetRemoteOptions(MIU) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
    400       return 0;
    401    }
    402 }
    403 
    404 static jint com_android_nfc_NativeLlcpSocket_doGetRemoteSocketRW(JNIEnv *e, jobject o)
    405 {
    406    NFCSTATUS ret;
    407    phLibNfc_Handle hRemoteDevice;
    408    phLibNfc_Handle hLlcpSocket;
    409    phLibNfc_Llcp_sSocketOptions_t   remoteSocketOption;
    410 
    411    /* Retrieve handles */
    412    hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o);
    413    hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
    414 
    415    TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(RW)");
    416    REENTRANCE_LOCK();
    417    ret  = phLibNfc_Llcp_SocketGetRemoteOptions(hRemoteDevice,
    418                                                hLlcpSocket,
    419                                                &remoteSocketOption);
    420    REENTRANCE_UNLOCK();
    421    if(ret == NFCSTATUS_SUCCESS)
    422    {
    423       TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(RW) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
    424       return remoteSocketOption.rw;
    425    }
    426    else
    427    {
    428       ALOGW("phLibNfc_Llcp_SocketGetRemoteOptions(RW) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
    429       return 0;
    430    }
    431 }
    432 
    433 
    434 /*
    435  * JNI registration.
    436  */
    437 static JNINativeMethod gMethods[] =
    438 {
    439    {"doConnect", "(I)Z",
    440       (void *)com_android_nfc_NativeLlcpSocket_doConnect},
    441 
    442    {"doConnectBy", "(Ljava/lang/String;)Z",
    443       (void *)com_android_nfc_NativeLlcpSocket_doConnectBy},
    444 
    445    {"doClose", "()Z",
    446       (void *)com_android_nfc_NativeLlcpSocket_doClose},
    447 
    448    {"doSend", "([B)Z",
    449       (void *)com_android_nfc_NativeLlcpSocket_doSend},
    450 
    451    {"doReceive", "([B)I",
    452       (void *)com_android_nfc_NativeLlcpSocket_doReceive},
    453 
    454    {"doGetRemoteSocketMiu", "()I",
    455       (void *)com_android_nfc_NativeLlcpSocket_doGetRemoteSocketMIU},
    456 
    457    {"doGetRemoteSocketRw", "()I",
    458       (void *)com_android_nfc_NativeLlcpSocket_doGetRemoteSocketRW},
    459 };
    460 
    461 
    462 int register_com_android_nfc_NativeLlcpSocket(JNIEnv *e)
    463 {
    464    return jniRegisterNativeMethods(e,
    465       "com/android/nfc/dhimpl/NativeLlcpSocket",gMethods, NELEM(gMethods));
    466 }
    467 
    468 } // namespace android
    469