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