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