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