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