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