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