Home | History | Annotate | Download | only in jni
      1 
      2 /*
      3  * Copyright (C) 2010 The Android Open Source Project
      4  *
      5  * Licensed under the Apache License, Version 2.0 (the "License");
      6  * you may not use this file except in compliance with the License.
      7  * You may obtain a copy of the License at
      8  *
      9  *      http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  */
     17 
     18 #include <semaphore.h>
     19 #include <errno.h>
     20 
     21 #include "com_android_nfc.h"
     22 
     23 extern uint8_t device_connected_flag;
     24 
     25 namespace android {
     26 
     27 extern void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat);
     28 
     29 /*
     30  * Callbacks
     31  */
     32 static void nfc_jni_presence_check_callback(void* pContext, NFCSTATUS status)
     33 {
     34    struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
     35    LOG_CALLBACK("nfc_jni_presence_check_callback", status);
     36 
     37    /* Report the callback status and wake up the caller */
     38    pCallbackData->status = status;
     39    sem_post(&pCallbackData->sem);
     40 }
     41 
     42 static void nfc_jni_connect_callback(void *pContext,
     43                                      phLibNfc_Handle hRemoteDev,
     44                                      phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status)
     45 {
     46    struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
     47    phNfc_sData_t * psGeneralBytes = (phNfc_sData_t *)pCallbackData->pContext;
     48    LOG_CALLBACK("nfc_jni_connect_callback", status);
     49 
     50    if(status == NFCSTATUS_SUCCESS)
     51    {
     52       psGeneralBytes->length = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length;
     53       psGeneralBytes->buffer = (uint8_t*)malloc(psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length);
     54       psGeneralBytes->buffer = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo;
     55    }
     56 
     57    /* Report the callback status and wake up the caller */
     58    pCallbackData->status = status;
     59    sem_post(&pCallbackData->sem);
     60 }
     61 
     62 static void nfc_jni_disconnect_callback(void *pContext, phLibNfc_Handle hRemoteDev, NFCSTATUS status)
     63 {
     64    struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
     65    LOG_CALLBACK("nfc_jni_disconnect_callback", status);
     66 
     67    /* Report the callback status and wake up the caller */
     68    pCallbackData->status = status;
     69    sem_post(&pCallbackData->sem);
     70 }
     71 
     72 static void nfc_jni_receive_callback(void *pContext, phNfc_sData_t *data, NFCSTATUS status)
     73 {
     74    struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
     75    phNfc_sData_t **ptr = (phNfc_sData_t **)pCallbackData->pContext;
     76    LOG_CALLBACK("nfc_jni_receive_callback", status);
     77 
     78    if(status == NFCSTATUS_SUCCESS)
     79    {
     80       *ptr = data;
     81    }
     82    else
     83    {
     84       *ptr = NULL;
     85    }
     86 
     87    /* Report the callback status and wake up the caller */
     88    pCallbackData->status = status;
     89    sem_post(&pCallbackData->sem);
     90 }
     91 
     92 static void nfc_jni_send_callback(void *pContext, NFCSTATUS status)
     93 {
     94    struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
     95    LOG_CALLBACK("nfc_jni_send_callback", status);
     96 
     97    /* Report the callback status and wake up the caller */
     98    pCallbackData->status = status;
     99    sem_post(&pCallbackData->sem);
    100 }
    101 
    102 /*
    103  * Functions
    104  */
    105 
    106 static void nfc_jni_transceive_callback(void *pContext,
    107   phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status)
    108 {
    109    struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
    110    LOG_CALLBACK("nfc_jni_transceive_callback", status);
    111 
    112    /* Report the callback data and wake up the caller */
    113    pCallbackData->pContext = pResBuffer;
    114    pCallbackData->status = status;
    115    sem_post(&pCallbackData->sem);
    116 }
    117 
    118 static jboolean com_android_nfc_NativeP2pDevice_doConnect(JNIEnv *e, jobject o)
    119 {
    120     phLibNfc_Handle handle = 0;
    121     NFCSTATUS status;
    122     jboolean result = JNI_FALSE;
    123     struct nfc_jni_callback_data cb_data;
    124 
    125     jclass target_cls = NULL;
    126     jobject tag;
    127     jmethodID ctor;
    128     jfieldID f;
    129     jbyteArray generalBytes = NULL;
    130     phNfc_sData_t sGeneralBytes;
    131     unsigned int i;
    132 
    133     CONCURRENCY_LOCK();
    134 
    135     handle = nfc_jni_get_p2p_device_handle(e, o);
    136 
    137     /* Create the local semaphore */
    138     if (!nfc_cb_data_init(&cb_data, (void*)&sGeneralBytes))
    139     {
    140        goto clean_and_return;
    141     }
    142 
    143     TRACE("phLibNfc_RemoteDev_Connect(P2P)");
    144     REENTRANCE_LOCK();
    145     status = phLibNfc_RemoteDev_Connect(handle, nfc_jni_connect_callback, (void*)&cb_data);
    146     REENTRANCE_UNLOCK();
    147     if(status != NFCSTATUS_PENDING)
    148     {
    149       LOGE("phLibNfc_RemoteDev_Connect(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
    150       goto clean_and_return;
    151     }
    152     TRACE("phLibNfc_RemoteDev_Connect(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
    153 
    154     /* Wait for callback response */
    155     if(sem_wait(&cb_data.sem))
    156     {
    157        LOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
    158        goto clean_and_return;
    159     }
    160 
    161     if(cb_data.status != NFCSTATUS_SUCCESS)
    162     {
    163         goto clean_and_return;
    164     }
    165 
    166     /* Set General Bytes */
    167     target_cls = e->GetObjectClass(o);
    168 
    169     f = e->GetFieldID(target_cls, "mGeneralBytes", "[B");
    170 
    171     TRACE("General Bytes Length = %d", sGeneralBytes.length);
    172     TRACE("General Bytes =");
    173     for(i=0;i<sGeneralBytes.length;i++)
    174     {
    175       TRACE("0x%02x ", sGeneralBytes.buffer[i]);
    176     }
    177 
    178     generalBytes = e->NewByteArray(sGeneralBytes.length);
    179 
    180     e->SetByteArrayRegion(generalBytes, 0,
    181                          sGeneralBytes.length,
    182                          (jbyte *)sGeneralBytes.buffer);
    183 
    184     e->SetObjectField(o, f, generalBytes);
    185 
    186     result = JNI_TRUE;
    187 
    188 clean_and_return:
    189     if (result != JNI_TRUE)
    190     {
    191        /* Restart the polling loop if the connection failed */
    192        nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e));
    193     }
    194     nfc_cb_data_deinit(&cb_data);
    195     CONCURRENCY_UNLOCK();
    196     return result;
    197 }
    198 
    199 static jboolean com_android_nfc_NativeP2pDevice_doDisconnect(JNIEnv *e, jobject o)
    200 {
    201     phLibNfc_Handle     handle = 0;
    202     jboolean            result = JNI_FALSE;
    203     NFCSTATUS           status;
    204     struct nfc_jni_callback_data cb_data;
    205 
    206     CONCURRENCY_LOCK();
    207 
    208     handle = nfc_jni_get_p2p_device_handle(e, o);
    209 
    210     /* Create the local semaphore */
    211     if (!nfc_cb_data_init(&cb_data, NULL))
    212     {
    213        goto clean_and_return;
    214     }
    215 
    216     /* Disconnect */
    217     TRACE("Disconnecting from target (handle = 0x%x)", handle);
    218 
    219     /* NativeNfcTag waits for tag to leave the field here with presence check.
    220      * We do not in P2P path because presence check is not safe while transceive may be
    221      * in progress.
    222      */
    223 
    224     TRACE("phLibNfc_RemoteDev_Disconnect()");
    225     REENTRANCE_LOCK();
    226     status = phLibNfc_RemoteDev_Disconnect(handle, NFC_DISCOVERY_CONTINUE,nfc_jni_disconnect_callback, (void *)&cb_data);
    227     REENTRANCE_UNLOCK();
    228     if(status != NFCSTATUS_PENDING)
    229     {
    230         LOGE("phLibNfc_RemoteDev_Disconnect() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
    231         if(status == NFCSTATUS_TARGET_NOT_CONNECTED)
    232         {
    233             LOGE("phLibNfc_RemoteDev_Disconnect() failed: Target not connected");
    234         }
    235         else
    236         {
    237             LOGE("phLibNfc_RemoteDev_Disconnect() failed");
    238             nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e));
    239         }
    240 
    241         goto clean_and_return;
    242     }
    243     TRACE("phLibNfc_RemoteDev_Disconnect() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
    244 
    245     /* Wait for callback response */
    246     if(sem_wait(&cb_data.sem))
    247     {
    248        LOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
    249        goto clean_and_return;
    250     }
    251 
    252     /* Disconnect Status */
    253     if(cb_data.status != NFCSTATUS_SUCCESS)
    254     {
    255         goto clean_and_return;
    256     }
    257 
    258     result = JNI_TRUE;
    259 
    260 clean_and_return:
    261     /* Reset device connected flag */
    262     device_connected_flag = 0;
    263     nfc_cb_data_deinit(&cb_data);
    264     CONCURRENCY_UNLOCK();
    265     return result;
    266 }
    267 
    268 static jbyteArray com_android_nfc_NativeP2pDevice_doTransceive(JNIEnv *e,
    269    jobject o, jbyteArray data)
    270 {
    271    NFCSTATUS status;
    272    uint8_t offset = 2;
    273    uint8_t *buf;
    274    uint32_t buflen;
    275    phLibNfc_sTransceiveInfo_t transceive_info;
    276    jbyteArray result = NULL;
    277    phLibNfc_Handle handle = nfc_jni_get_p2p_device_handle(e, o);
    278    phNfc_sData_t * receive_buffer = NULL;
    279    struct nfc_jni_callback_data cb_data;
    280 
    281    CONCURRENCY_LOCK();
    282 
    283    /* Create the local semaphore */
    284    if (!nfc_cb_data_init(&cb_data, (void*)receive_buffer))
    285    {
    286       goto clean_and_return;
    287    }
    288 
    289    /* Transceive*/
    290    TRACE("Transceive data to target (handle = 0x%x)", handle);
    291 
    292    buf = (uint8_t *)e->GetByteArrayElements(data, NULL);
    293    buflen = (uint32_t)e->GetArrayLength(data);
    294 
    295    TRACE("Buffer Length = %d\n", buflen);
    296 
    297    transceive_info.sSendData.buffer = buf; //+ offset;
    298    transceive_info.sSendData.length = buflen; //- offset;
    299    transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024);
    300    transceive_info.sRecvData.length = 1024;
    301 
    302    if(transceive_info.sRecvData.buffer == NULL)
    303    {
    304       goto clean_and_return;
    305    }
    306 
    307    TRACE("phLibNfc_RemoteDev_Transceive(P2P)");
    308    REENTRANCE_LOCK();
    309    status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info, nfc_jni_transceive_callback, (void *)&cb_data);
    310    REENTRANCE_UNLOCK();
    311    if(status != NFCSTATUS_PENDING)
    312    {
    313       LOGE("phLibNfc_RemoteDev_Transceive(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
    314       goto clean_and_return;
    315    }
    316    TRACE("phLibNfc_RemoteDev_Transceive(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
    317 
    318    /* Wait for callback response */
    319    if(sem_wait(&cb_data.sem))
    320    {
    321       LOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
    322       goto clean_and_return;
    323    }
    324 
    325    if(cb_data.status != NFCSTATUS_SUCCESS)
    326    {
    327       goto clean_and_return;
    328    }
    329 
    330    /* Copy results back to Java */
    331    result = e->NewByteArray(receive_buffer->length);
    332    if(result != NULL)
    333       e->SetByteArrayRegion(result, 0,
    334          receive_buffer->length,
    335          (jbyte *)receive_buffer->buffer);
    336 
    337 clean_and_return:
    338    if(transceive_info.sRecvData.buffer != NULL)
    339    {
    340       free(transceive_info.sRecvData.buffer);
    341    }
    342 
    343    e->ReleaseByteArrayElements(data,
    344       (jbyte *)transceive_info.sSendData.buffer, JNI_ABORT);
    345 
    346    nfc_cb_data_deinit(&cb_data);
    347 
    348    CONCURRENCY_UNLOCK();
    349 
    350    return result;
    351 }
    352 
    353 
    354 static jbyteArray com_android_nfc_NativeP2pDevice_doReceive(
    355    JNIEnv *e, jobject o)
    356 {
    357    NFCSTATUS status;
    358    struct timespec ts;
    359    phLibNfc_Handle handle;
    360    jbyteArray buf = NULL;
    361    static phNfc_sData_t *data;
    362    struct nfc_jni_callback_data cb_data;
    363 
    364    CONCURRENCY_LOCK();
    365 
    366    handle = nfc_jni_get_p2p_device_handle(e, o);
    367 
    368    /* Create the local semaphore */
    369    if (!nfc_cb_data_init(&cb_data, (void*)data))
    370    {
    371       goto clean_and_return;
    372    }
    373 
    374    /* Receive */
    375    TRACE("phLibNfc_RemoteDev_Receive()");
    376    REENTRANCE_LOCK();
    377    status = phLibNfc_RemoteDev_Receive(handle, nfc_jni_receive_callback,(void *)&cb_data);
    378    REENTRANCE_UNLOCK();
    379    if(status != NFCSTATUS_PENDING)
    380    {
    381       LOGE("phLibNfc_RemoteDev_Receive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
    382       goto clean_and_return;
    383    }
    384    TRACE("phLibNfc_RemoteDev_Receive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
    385 
    386    /* Wait for callback response */
    387    if(sem_wait(&cb_data.sem))
    388    {
    389       LOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
    390       goto clean_and_return;
    391    }
    392 
    393    if(data == NULL)
    394    {
    395       goto clean_and_return;
    396    }
    397 
    398    buf = e->NewByteArray(data->length);
    399    e->SetByteArrayRegion(buf, 0, data->length, (jbyte *)data->buffer);
    400 
    401 clean_and_return:
    402    nfc_cb_data_deinit(&cb_data);
    403    CONCURRENCY_UNLOCK();
    404    return buf;
    405 }
    406 
    407 static jboolean com_android_nfc_NativeP2pDevice_doSend(
    408    JNIEnv *e, jobject o, jbyteArray buf)
    409 {
    410    NFCSTATUS status;
    411    phNfc_sData_t data;
    412    jboolean result = JNI_FALSE;
    413    struct nfc_jni_callback_data cb_data;
    414 
    415    phLibNfc_Handle handle = nfc_jni_get_p2p_device_handle(e, o);
    416 
    417    CONCURRENCY_LOCK();
    418 
    419    /* Create the local semaphore */
    420    if (!nfc_cb_data_init(&cb_data, NULL))
    421    {
    422       goto clean_and_return;
    423    }
    424 
    425    /* Send */
    426    TRACE("Send data to the Initiator (handle = 0x%x)", handle);
    427 
    428    data.length = (uint32_t)e->GetArrayLength(buf);
    429    data.buffer = (uint8_t *)e->GetByteArrayElements(buf, NULL);
    430 
    431    TRACE("phLibNfc_RemoteDev_Send()");
    432    REENTRANCE_LOCK();
    433    status = phLibNfc_RemoteDev_Send(handle, &data, nfc_jni_send_callback,(void *)&cb_data);
    434    REENTRANCE_UNLOCK();
    435    if(status != NFCSTATUS_PENDING)
    436    {
    437       LOGE("phLibNfc_RemoteDev_Send() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
    438       goto clean_and_return;
    439    }
    440    TRACE("phLibNfc_RemoteDev_Send() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
    441 
    442    /* Wait for callback response */
    443    if(sem_wait(&cb_data.sem))
    444    {
    445       LOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
    446       goto clean_and_return;
    447    }
    448 
    449    if(cb_data.status != NFCSTATUS_SUCCESS)
    450    {
    451       goto clean_and_return;
    452    }
    453 
    454    result = JNI_TRUE;
    455 
    456 clean_and_return:
    457    if (result != JNI_TRUE)
    458    {
    459       e->ReleaseByteArrayElements(buf, (jbyte *)data.buffer, JNI_ABORT);
    460    }
    461    nfc_cb_data_deinit(&cb_data);
    462    CONCURRENCY_UNLOCK();
    463    return result;
    464 }
    465 
    466 /*
    467  * JNI registration.
    468  */
    469 static JNINativeMethod gMethods[] =
    470 {
    471    {"doConnect", "()Z",
    472       (void *)com_android_nfc_NativeP2pDevice_doConnect},
    473    {"doDisconnect", "()Z",
    474       (void *)com_android_nfc_NativeP2pDevice_doDisconnect},
    475    {"doTransceive", "([B)[B",
    476       (void *)com_android_nfc_NativeP2pDevice_doTransceive},
    477    {"doReceive", "()[B",
    478       (void *)com_android_nfc_NativeP2pDevice_doReceive},
    479    {"doSend", "([B)Z",
    480       (void *)com_android_nfc_NativeP2pDevice_doSend},
    481 };
    482 
    483 int register_com_android_nfc_NativeP2pDevice(JNIEnv *e)
    484 {
    485    return jniRegisterNativeMethods(e,
    486       "com/android/nfc/nxp/NativeP2pDevice",
    487       gMethods, NELEM(gMethods));
    488 }
    489 
    490 } // namepspace android
    491