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