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 */
nfc_jni_presence_check_callback(void * pContext,NFCSTATUS status)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
nfc_jni_connect_callback(void * pContext,phLibNfc_Handle,phLibNfc_sRemoteDevInformation_t * psRemoteDevInfo,NFCSTATUS status)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
nfc_jni_disconnect_callback(void * pContext,phLibNfc_Handle,NFCSTATUS status)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
nfc_jni_receive_callback(void * pContext,phNfc_sData_t * data,NFCSTATUS status)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
nfc_jni_send_callback(void * pContext,NFCSTATUS status)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
nfc_jni_transceive_callback(void * pContext,phLibNfc_Handle,phNfc_sData_t * pResBuffer,NFCSTATUS status)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
com_android_nfc_NativeP2pDevice_doConnect(JNIEnv * e,jobject o)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
com_android_nfc_NativeP2pDevice_doDisconnect(JNIEnv * e,jobject o)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
com_android_nfc_NativeP2pDevice_doTransceive(JNIEnv * e,jobject o,jbyteArray data)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
com_android_nfc_NativeP2pDevice_doReceive(JNIEnv * e,jobject o)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
com_android_nfc_NativeP2pDevice_doSend(JNIEnv * e,jobject o,jbyteArray buf)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
register_com_android_nfc_NativeP2pDevice(JNIEnv * e)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