• 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 <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