• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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