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