/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <semaphore.h> #include <errno.h> #include "com_android_nfc.h" namespace android { /* * Callbacks */ static void nfc_jni_disconnect_callback(void* pContext, NFCSTATUS status) { struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; LOG_CALLBACK("nfc_jni_disconnect_callback", status); /* Report the callback status and wake up the caller */ pCallbackData->status = status; sem_post(&pCallbackData->sem); } static void nfc_jni_connect_callback(void* pContext, uint8_t nErrCode, NFCSTATUS status) { struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; LOG_CALLBACK("nfc_jni_llcp_connect_callback", status); if(status == NFCSTATUS_SUCCESS) { TRACE("Socket connected\n"); } else { LOGD("Socket not connected:"); switch(nErrCode) { case PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_ACTIVE: { LOGD("> SAP NOT ACTIVE\n"); }break; case PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_FOUND: { LOGD("> SAP NOT FOUND\n"); }break; case PHFRINFC_LLCP_DM_OPCODE_CONNECT_REJECTED: { LOGD("> CONNECT REJECTED\n"); }break; case PHFRINFC_LLCP_DM_OPCODE_CONNECT_NOT_ACCEPTED: { LOGD("> CONNECT NOT ACCEPTED\n"); }break; case PHFRINFC_LLCP_DM_OPCODE_SOCKET_NOT_AVAILABLE: { LOGD("> SOCKET NOT AVAILABLE\n"); }break; } } /* Report the callback status and wake up the caller */ pCallbackData->status = status; sem_post(&pCallbackData->sem); } static void nfc_jni_receive_callback(void* pContext, NFCSTATUS status) { struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; LOG_CALLBACK("nfc_jni_llcp_receive_callback", status); /* Report the callback status and wake up the caller */ pCallbackData->status = status; sem_post(&pCallbackData->sem); } static void nfc_jni_send_callback(void *pContext, NFCSTATUS status) { struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; LOG_CALLBACK("nfc_jni_llcp_send_callback", status); /* Report the callback status and wake up the caller */ pCallbackData->status = status; sem_post(&pCallbackData->sem); } /* * Methods */ static jboolean com_android_nfc_NativeLlcpSocket_doConnect(JNIEnv *e, jobject o, jint nSap) { NFCSTATUS ret; struct timespec ts; phLibNfc_Handle hRemoteDevice; phLibNfc_Handle hLlcpSocket; struct nfc_jni_callback_data cb_data; jboolean result = JNI_FALSE; /* Retrieve handles */ hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); /* Create the local semaphore */ if (!nfc_cb_data_init(&cb_data, NULL)) { goto clean_and_return; } TRACE("phLibNfc_Llcp_Connect(%d)",nSap); REENTRANCE_LOCK(); ret = phLibNfc_Llcp_Connect(hRemoteDevice, hLlcpSocket, nSap, nfc_jni_connect_callback, (void*)&cb_data); REENTRANCE_UNLOCK(); if(ret != NFCSTATUS_PENDING) { LOGE("phLibNfc_Llcp_Connect(%d) returned 0x%04x[%s]", nSap, ret, nfc_jni_get_status_name(ret)); goto clean_and_return; } TRACE("phLibNfc_Llcp_Connect(%d) returned 0x%04x[%s]", nSap, ret, nfc_jni_get_status_name(ret)); /* Wait for callback response */ if(sem_wait(&cb_data.sem)) { LOGE("Failed to wait for semaphore (errno=0x%08x)", errno); goto clean_and_return; } if(cb_data.status != NFCSTATUS_SUCCESS) { LOGW("LLCP Connect request failed"); goto clean_and_return; } result = JNI_TRUE; clean_and_return: nfc_cb_data_deinit(&cb_data); return result; } static jboolean com_android_nfc_NativeLlcpSocket_doConnectBy(JNIEnv *e, jobject o, jstring sn) { NFCSTATUS ret; struct timespec ts; phNfc_sData_t serviceName; phLibNfc_Handle hRemoteDevice; phLibNfc_Handle hLlcpSocket; struct nfc_jni_callback_data cb_data; jboolean result = JNI_FALSE; /* Retrieve handles */ hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); /* Create the local semaphore */ if (!nfc_cb_data_init(&cb_data, NULL)) { goto clean_and_return; } /* Service socket */ serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL); serviceName.length = (uint32_t)e->GetStringUTFLength(sn); TRACE("phLibNfc_Llcp_ConnectByUri()"); REENTRANCE_LOCK(); ret = phLibNfc_Llcp_ConnectByUri(hRemoteDevice, hLlcpSocket, &serviceName, nfc_jni_connect_callback, (void*)&cb_data); REENTRANCE_UNLOCK(); if(ret != NFCSTATUS_PENDING) { LOGE("phLibNfc_Llcp_ConnectByUri() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); goto clean_and_return; } TRACE("phLibNfc_Llcp_ConnectByUri() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); /* Wait for callback response */ if(sem_wait(&cb_data.sem)) { LOGE("Failed to wait for semaphore (errno=0x%08x)", errno); goto clean_and_return; } if(cb_data.status != NFCSTATUS_SUCCESS) { goto clean_and_return; } result = JNI_TRUE; clean_and_return: nfc_cb_data_deinit(&cb_data); return result; } static jboolean com_android_nfc_NativeLlcpSocket_doClose(JNIEnv *e, jobject o) { NFCSTATUS ret; phLibNfc_Handle hLlcpSocket; /* Retrieve socket handle */ hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); TRACE("phLibNfc_Llcp_Close()"); REENTRANCE_LOCK(); ret = phLibNfc_Llcp_Close(hLlcpSocket); REENTRANCE_UNLOCK(); if(ret != NFCSTATUS_SUCCESS) { LOGE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); return FALSE; } TRACE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); return TRUE; } static jboolean com_android_nfc_NativeLlcpSocket_doSend(JNIEnv *e, jobject o, jbyteArray data) { NFCSTATUS ret; struct timespec ts; phLibNfc_Handle hRemoteDevice; phLibNfc_Handle hLlcpSocket; phNfc_sData_t sSendBuffer = {NULL, 0}; struct nfc_jni_callback_data cb_data; jboolean result = JNI_FALSE; /* Retrieve handles */ hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); /* Create the local semaphore */ if (!nfc_cb_data_init(&cb_data, NULL)) { goto clean_and_return; } sSendBuffer.buffer = (uint8_t*)e->GetByteArrayElements(data, NULL); sSendBuffer.length = (uint32_t)e->GetArrayLength(data); TRACE("phLibNfc_Llcp_Send()"); REENTRANCE_LOCK(); ret = phLibNfc_Llcp_Send(hRemoteDevice, hLlcpSocket, &sSendBuffer, nfc_jni_send_callback, (void*)&cb_data); REENTRANCE_UNLOCK(); if(ret != NFCSTATUS_PENDING) { LOGE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); goto clean_and_return; } TRACE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); /* Wait for callback response */ if(sem_wait(&cb_data.sem)) { LOGE("Failed to wait for semaphore (errno=0x%08x)", errno); goto clean_and_return; } if(cb_data.status != NFCSTATUS_SUCCESS) { goto clean_and_return; } result = JNI_TRUE; clean_and_return: if (sSendBuffer.buffer != NULL) { e->ReleaseByteArrayElements(data, (jbyte*)sSendBuffer.buffer, JNI_ABORT); } nfc_cb_data_deinit(&cb_data); return result; } static jint com_android_nfc_NativeLlcpSocket_doReceive(JNIEnv *e, jobject o, jbyteArray buffer) { NFCSTATUS ret; struct timespec ts; phLibNfc_Handle hRemoteDevice; phLibNfc_Handle hLlcpSocket; phNfc_sData_t sReceiveBuffer = {NULL, 0}; struct nfc_jni_callback_data cb_data; jint result = -1; /* Retrieve handles */ hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); /* Create the local semaphore */ if (!nfc_cb_data_init(&cb_data, NULL)) { goto clean_and_return; } sReceiveBuffer.buffer = (uint8_t*)e->GetByteArrayElements(buffer, NULL); sReceiveBuffer.length = (uint32_t)e->GetArrayLength(buffer); TRACE("phLibNfc_Llcp_Recv()"); REENTRANCE_LOCK(); ret = phLibNfc_Llcp_Recv(hRemoteDevice, hLlcpSocket, &sReceiveBuffer, nfc_jni_receive_callback, (void*)&cb_data); REENTRANCE_UNLOCK(); if(ret == NFCSTATUS_PENDING) { /* Wait for callback response */ if(sem_wait(&cb_data.sem)) { LOGE("Failed to wait for semaphore (errno=0x%08x)", errno); goto clean_and_return; } if(cb_data.status == NFCSTATUS_SUCCESS) { result = sReceiveBuffer.length; } } else if (ret == NFCSTATUS_SUCCESS) { result = sReceiveBuffer.length; } else { /* Return status should be either SUCCESS or PENDING */ LOGE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); goto clean_and_return; } TRACE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); clean_and_return: if (sReceiveBuffer.buffer != NULL) { e->ReleaseByteArrayElements(buffer, (jbyte*)sReceiveBuffer.buffer, 0); } nfc_cb_data_deinit(&cb_data); return result; } static jint com_android_nfc_NativeLlcpSocket_doGetRemoteSocketMIU(JNIEnv *e, jobject o) { NFCSTATUS ret; phLibNfc_Handle hRemoteDevice; phLibNfc_Handle hLlcpSocket; phLibNfc_Llcp_sSocketOptions_t remoteSocketOption; /* Retrieve handles */ hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(MIU)"); REENTRANCE_LOCK(); ret = phLibNfc_Llcp_SocketGetRemoteOptions(hRemoteDevice, hLlcpSocket, &remoteSocketOption); REENTRANCE_UNLOCK(); if(ret == NFCSTATUS_SUCCESS) { TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(MIU) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); return remoteSocketOption.miu; } else { LOGW("phLibNfc_Llcp_SocketGetRemoteOptions(MIU) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); return 0; } } static jint com_android_nfc_NativeLlcpSocket_doGetRemoteSocketRW(JNIEnv *e, jobject o) { NFCSTATUS ret; phLibNfc_Handle hRemoteDevice; phLibNfc_Handle hLlcpSocket; phLibNfc_Llcp_sSocketOptions_t remoteSocketOption; /* Retrieve handles */ hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(RW)"); REENTRANCE_LOCK(); ret = phLibNfc_Llcp_SocketGetRemoteOptions(hRemoteDevice, hLlcpSocket, &remoteSocketOption); REENTRANCE_UNLOCK(); if(ret == NFCSTATUS_SUCCESS) { TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(RW) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); return remoteSocketOption.rw; } else { LOGW("phLibNfc_Llcp_SocketGetRemoteOptions(RW) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); return 0; } } /* * JNI registration. */ static JNINativeMethod gMethods[] = { {"doConnect", "(I)Z", (void *)com_android_nfc_NativeLlcpSocket_doConnect}, {"doConnectBy", "(Ljava/lang/String;)Z", (void *)com_android_nfc_NativeLlcpSocket_doConnectBy}, {"doClose", "()Z", (void *)com_android_nfc_NativeLlcpSocket_doClose}, {"doSend", "([B)Z", (void *)com_android_nfc_NativeLlcpSocket_doSend}, {"doReceive", "([B)I", (void *)com_android_nfc_NativeLlcpSocket_doReceive}, {"doGetRemoteSocketMiu", "()I", (void *)com_android_nfc_NativeLlcpSocket_doGetRemoteSocketMIU}, {"doGetRemoteSocketRw", "()I", (void *)com_android_nfc_NativeLlcpSocket_doGetRemoteSocketRW}, }; int register_com_android_nfc_NativeLlcpSocket(JNIEnv *e) { return jniRegisterNativeMethods(e, "com/android/nfc/nxp/NativeLlcpSocket",gMethods, NELEM(gMethods)); } } // namespace android