1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <stdlib.h>
18 
19 #include "errno.h"
20 #include "com_android_nfc.h"
21 #include "com_android_nfc_list.h"
22 #include "phLibNfcStatus.h"
23 #include <ScopedLocalRef.h>
24 
25 /*
26  * JNI Initialization
27  */
JNI_OnLoad(JavaVM * jvm,void *)28 jint JNI_OnLoad(JavaVM *jvm, void* /*reserved*/)
29 {
30    JNIEnv *e;
31 
32    ALOGI("NFC Service: loading nxp JNI");
33 
34    // Check JNI version
35    if(jvm->GetEnv((void **)&e, JNI_VERSION_1_6))
36       return JNI_ERR;
37 
38    android::vm = jvm;
39 
40    if (android::register_com_android_nfc_NativeNfcManager(e) == -1)
41       return JNI_ERR;
42    if (android::register_com_android_nfc_NativeNfcTag(e) == -1)
43       return JNI_ERR;
44    if (android::register_com_android_nfc_NativeP2pDevice(e) == -1)
45       return JNI_ERR;
46    if (android::register_com_android_nfc_NativeLlcpSocket(e) == -1)
47       return JNI_ERR;
48    if (android::register_com_android_nfc_NativeLlcpConnectionlessSocket(e) == -1)
49       return JNI_ERR;
50    if (android::register_com_android_nfc_NativeLlcpServiceSocket(e) == -1)
51       return JNI_ERR;
52 
53    return JNI_VERSION_1_6;
54 }
55 
56 namespace android {
57 
58 extern struct nfc_jni_native_data *exported_nat;
59 
60 JavaVM *vm;
61 
62 /*
63  * JNI Utils
64  */
nfc_get_env()65 JNIEnv *nfc_get_env()
66 {
67     JNIEnv *e;
68     if (vm->GetEnv((void **)&e, JNI_VERSION_1_6) != JNI_OK) {
69         ALOGE("Current thread is not attached to VM");
70         phLibNfc_Mgt_Recovery();
71         abort();
72     }
73     return e;
74 }
75 
nfc_cb_data_init(nfc_jni_callback_data * pCallbackData,void * pContext)76 bool nfc_cb_data_init(nfc_jni_callback_data* pCallbackData, void* pContext)
77 {
78    /* Create semaphore */
79    if(sem_init(&pCallbackData->sem, 0, 0) == -1)
80    {
81       ALOGE("Semaphore creation failed (errno=0x%08x)", errno);
82       return false;
83    }
84 
85    /* Set default status value */
86    pCallbackData->status = NFCSTATUS_FAILED;
87 
88    /* Copy the context */
89    pCallbackData->pContext = pContext;
90 
91    /* Add to active semaphore list */
92    if (!listAdd(&nfc_jni_get_monitor()->sem_list, pCallbackData))
93    {
94       ALOGE("Failed to add the semaphore to the list");
95    }
96 
97    return true;
98 }
99 
nfc_cb_data_deinit(nfc_jni_callback_data * pCallbackData)100 void nfc_cb_data_deinit(nfc_jni_callback_data* pCallbackData)
101 {
102    /* Destroy semaphore */
103    if (sem_destroy(&pCallbackData->sem))
104    {
105       ALOGE("Failed to destroy semaphore (errno=0x%08x)", errno);
106    }
107 
108    /* Remove from active semaphore list */
109    if (!listRemove(&nfc_jni_get_monitor()->sem_list, pCallbackData))
110    {
111       ALOGE("Failed to remove semaphore from the list");
112    }
113 
114 }
115 
nfc_cb_data_releaseAll()116 void nfc_cb_data_releaseAll()
117 {
118    nfc_jni_callback_data* pCallbackData;
119 
120    while (listGetAndRemoveNext(&nfc_jni_get_monitor()->sem_list, (void**)&pCallbackData))
121    {
122       pCallbackData->status = NFCSTATUS_FAILED;
123       sem_post(&pCallbackData->sem);
124    }
125 }
126 
nfc_jni_cache_object(JNIEnv * e,const char * clsname,jobject * cached_obj)127 int nfc_jni_cache_object(JNIEnv *e, const char *clsname,
128    jobject *cached_obj)
129 {
130    ScopedLocalRef<jclass> cls(e, e->FindClass(clsname));
131    if (cls.get() == NULL) {
132       ALOGD("Find class error\n");
133       return -1;
134    }
135 
136    jmethodID ctor = e->GetMethodID(cls.get(), "<init>", "()V");
137    ScopedLocalRef<jobject> obj(e, e->NewObject(cls.get(), ctor));
138    if (obj.get() == NULL) {
139       ALOGD("Create object error\n");
140       return -1;
141    }
142 
143    *cached_obj = e->NewGlobalRef(obj.get());
144    if (*cached_obj == NULL) {
145       ALOGD("Global ref error\n");
146       return -1;
147    }
148 
149    return 0;
150 }
151 
152 
nfc_jni_get_nat(JNIEnv * e,jobject o)153 struct nfc_jni_native_data* nfc_jni_get_nat(JNIEnv *e, jobject o)
154 {
155    /* Retrieve native structure address */
156    ScopedLocalRef<jclass> c(e, e->GetObjectClass(o));
157    jfieldID f = e->GetFieldID(c.get(), "mNative", "J");
158    return (struct nfc_jni_native_data*) e->GetLongField(o, f);
159 }
160 
nfc_jni_get_nat_ext(JNIEnv *)161 struct nfc_jni_native_data* nfc_jni_get_nat_ext(JNIEnv*)
162 {
163    return exported_nat;
164 }
165 
166 static nfc_jni_native_monitor_t *nfc_jni_native_monitor = NULL;
167 
nfc_jni_init_monitor(void)168 nfc_jni_native_monitor_t* nfc_jni_init_monitor(void)
169 {
170 
171    pthread_mutexattr_t recursive_attr;
172 
173    pthread_mutexattr_init(&recursive_attr);
174    pthread_mutexattr_settype(&recursive_attr, PTHREAD_MUTEX_RECURSIVE_NP);
175 
176    if(nfc_jni_native_monitor == NULL)
177    {
178       nfc_jni_native_monitor = (nfc_jni_native_monitor_t*)malloc(sizeof(nfc_jni_native_monitor_t));
179    }
180 
181    if(nfc_jni_native_monitor != NULL)
182    {
183       memset(nfc_jni_native_monitor, 0, sizeof(nfc_jni_native_monitor_t));
184 
185       if(pthread_mutex_init(&nfc_jni_native_monitor->reentrance_mutex, &recursive_attr) == -1)
186       {
187          ALOGE("NFC Manager Reentrance Mutex creation returned 0x%08x", errno);
188          return NULL;
189       }
190 
191       if(pthread_mutex_init(&nfc_jni_native_monitor->concurrency_mutex, NULL) == -1)
192       {
193          ALOGE("NFC Manager Concurrency Mutex creation returned 0x%08x", errno);
194          return NULL;
195       }
196 
197       if(!listInit(&nfc_jni_native_monitor->sem_list))
198       {
199          ALOGE("NFC Manager Semaphore List creation failed");
200          return NULL;
201       }
202 
203       LIST_INIT(&nfc_jni_native_monitor->incoming_socket_head);
204 
205       if(pthread_mutex_init(&nfc_jni_native_monitor->incoming_socket_mutex, NULL) == -1)
206       {
207          ALOGE("NFC Manager incoming socket mutex creation returned 0x%08x", errno);
208          return NULL;
209       }
210 
211       if(pthread_cond_init(&nfc_jni_native_monitor->incoming_socket_cond, NULL) == -1)
212       {
213          ALOGE("NFC Manager incoming socket condition creation returned 0x%08x", errno);
214          return NULL;
215       }
216 
217 }
218 
219    return nfc_jni_native_monitor;
220 }
221 
nfc_jni_get_monitor(void)222 nfc_jni_native_monitor_t* nfc_jni_get_monitor(void)
223 {
224    return nfc_jni_native_monitor;
225 }
226 
227 
nfc_jni_get_p2p_device_handle(JNIEnv * e,jobject o)228 phLibNfc_Handle nfc_jni_get_p2p_device_handle(JNIEnv *e, jobject o)
229 {
230    ScopedLocalRef<jclass> c(e, e->GetObjectClass(o));
231    jfieldID f = e->GetFieldID(c.get(), "mHandle", "I");
232    return e->GetIntField(o, f);
233 }
234 
nfc_jni_get_p2p_device_mode(JNIEnv * e,jobject o)235 jshort nfc_jni_get_p2p_device_mode(JNIEnv *e, jobject o)
236 {
237    ScopedLocalRef<jclass> c(e, e->GetObjectClass(o));
238    jfieldID f = e->GetFieldID(c.get(), "mMode", "S");
239    return e->GetShortField(o, f);
240 }
241 
242 
nfc_jni_get_connected_tech_index(JNIEnv * e,jobject o)243 int nfc_jni_get_connected_tech_index(JNIEnv *e, jobject o)
244 {
245    ScopedLocalRef<jclass> c(e, e->GetObjectClass(o));
246    jfieldID f = e->GetFieldID(c.get(), "mConnectedTechIndex", "I");
247    return e->GetIntField(o, f);
248 
249 }
250 
nfc_jni_get_connected_technology(JNIEnv * e,jobject o)251 jint nfc_jni_get_connected_technology(JNIEnv *e, jobject o)
252 {
253    int connectedTech = -1;
254 
255    int connectedTechIndex = nfc_jni_get_connected_tech_index(e,o);
256    jintArray techTypes = nfc_jni_get_nfc_tag_type(e, o);
257 
258    if ((connectedTechIndex != -1) && (techTypes != NULL) &&
259            (connectedTechIndex < e->GetArrayLength(techTypes))) {
260        jint* technologies = e->GetIntArrayElements(techTypes, 0);
261        if (technologies != NULL) {
262            connectedTech = technologies[connectedTechIndex];
263            e->ReleaseIntArrayElements(techTypes, technologies, JNI_ABORT);
264        }
265    }
266 
267    return connectedTech;
268 
269 }
270 
nfc_jni_get_connected_technology_libnfc_type(JNIEnv * e,jobject o)271 jint nfc_jni_get_connected_technology_libnfc_type(JNIEnv *e, jobject o)
272 {
273    jint connectedLibNfcType = -1;
274 
275    int connectedTechIndex = nfc_jni_get_connected_tech_index(e,o);
276    ScopedLocalRef<jclass> c(e, e->GetObjectClass(o));
277    jfieldID f = e->GetFieldID(c.get(), "mTechLibNfcTypes", "[I");
278    ScopedLocalRef<jintArray> libNfcTypes(e, (jintArray) e->GetObjectField(o, f));
279 
280    if ((connectedTechIndex != -1) && (libNfcTypes.get() != NULL) &&
281            (connectedTechIndex < e->GetArrayLength(libNfcTypes.get()))) {
282        jint* types = e->GetIntArrayElements(libNfcTypes.get(), 0);
283        if (types != NULL) {
284            connectedLibNfcType = types[connectedTechIndex];
285            e->ReleaseIntArrayElements(libNfcTypes.get(), types, JNI_ABORT);
286        }
287    }
288    return connectedLibNfcType;
289 }
290 
nfc_jni_get_connected_handle(JNIEnv * e,jobject o)291 phLibNfc_Handle nfc_jni_get_connected_handle(JNIEnv *e, jobject o)
292 {
293    ScopedLocalRef<jclass> c(e, e->GetObjectClass(o));
294    jfieldID f = e->GetFieldID(c.get(), "mConnectedHandle", "I");
295    return e->GetIntField(o, f);
296 }
297 
nfc_jni_get_nfc_socket_handle(JNIEnv * e,jobject o)298 phLibNfc_Handle nfc_jni_get_nfc_socket_handle(JNIEnv *e, jobject o)
299 {
300    ScopedLocalRef<jclass> c(e, e->GetObjectClass(o));
301    jfieldID f = e->GetFieldID(c.get(), "mHandle", "I");
302    return e->GetIntField(o, f);
303 }
304 
nfc_jni_get_nfc_tag_type(JNIEnv * e,jobject o)305 jintArray nfc_jni_get_nfc_tag_type(JNIEnv *e, jobject o)
306 {
307    ScopedLocalRef<jclass> c(e, e->GetObjectClass(o));
308    jfieldID f = e->GetFieldID(c.get(), "mTechList","[I");
309    return (jintArray) e->GetObjectField(o, f);
310 }
311 
312 
313 
314 //Display status code
nfc_jni_get_status_name(NFCSTATUS status)315 const char* nfc_jni_get_status_name(NFCSTATUS status)
316 {
317    #define STATUS_ENTRY(status) { status, #status }
318 
319    struct status_entry {
320       NFCSTATUS   code;
321       const char  *name;
322    };
323 
324    const struct status_entry sNameTable[] = {
325       STATUS_ENTRY(NFCSTATUS_SUCCESS),
326       STATUS_ENTRY(NFCSTATUS_FAILED),
327       STATUS_ENTRY(NFCSTATUS_INVALID_PARAMETER),
328       STATUS_ENTRY(NFCSTATUS_INSUFFICIENT_RESOURCES),
329       STATUS_ENTRY(NFCSTATUS_TARGET_LOST),
330       STATUS_ENTRY(NFCSTATUS_INVALID_HANDLE),
331       STATUS_ENTRY(NFCSTATUS_MULTIPLE_TAGS),
332       STATUS_ENTRY(NFCSTATUS_ALREADY_REGISTERED),
333       STATUS_ENTRY(NFCSTATUS_FEATURE_NOT_SUPPORTED),
334       STATUS_ENTRY(NFCSTATUS_SHUTDOWN),
335       STATUS_ENTRY(NFCSTATUS_ABORTED),
336       STATUS_ENTRY(NFCSTATUS_REJECTED ),
337       STATUS_ENTRY(NFCSTATUS_NOT_INITIALISED),
338       STATUS_ENTRY(NFCSTATUS_PENDING),
339       STATUS_ENTRY(NFCSTATUS_BUFFER_TOO_SMALL),
340       STATUS_ENTRY(NFCSTATUS_ALREADY_INITIALISED),
341       STATUS_ENTRY(NFCSTATUS_BUSY),
342       STATUS_ENTRY(NFCSTATUS_TARGET_NOT_CONNECTED),
343       STATUS_ENTRY(NFCSTATUS_MULTIPLE_PROTOCOLS),
344       STATUS_ENTRY(NFCSTATUS_DESELECTED),
345       STATUS_ENTRY(NFCSTATUS_INVALID_DEVICE),
346       STATUS_ENTRY(NFCSTATUS_MORE_INFORMATION),
347       STATUS_ENTRY(NFCSTATUS_RF_TIMEOUT),
348       STATUS_ENTRY(NFCSTATUS_RF_ERROR),
349       STATUS_ENTRY(NFCSTATUS_BOARD_COMMUNICATION_ERROR),
350       STATUS_ENTRY(NFCSTATUS_INVALID_STATE),
351       STATUS_ENTRY(NFCSTATUS_NOT_REGISTERED),
352       STATUS_ENTRY(NFCSTATUS_RELEASED),
353       STATUS_ENTRY(NFCSTATUS_NOT_ALLOWED),
354       STATUS_ENTRY(NFCSTATUS_INVALID_REMOTE_DEVICE),
355       STATUS_ENTRY(NFCSTATUS_SMART_TAG_FUNC_NOT_SUPPORTED),
356       STATUS_ENTRY(NFCSTATUS_READ_FAILED),
357       STATUS_ENTRY(NFCSTATUS_WRITE_FAILED),
358       STATUS_ENTRY(NFCSTATUS_NO_NDEF_SUPPORT),
359       STATUS_ENTRY(NFCSTATUS_EOF_NDEF_CONTAINER_REACHED),
360       STATUS_ENTRY(NFCSTATUS_INVALID_RECEIVE_LENGTH),
361       STATUS_ENTRY(NFCSTATUS_INVALID_FORMAT),
362       STATUS_ENTRY(NFCSTATUS_INSUFFICIENT_STORAGE),
363       STATUS_ENTRY(NFCSTATUS_FORMAT_ERROR),
364    };
365 
366    int i = sizeof(sNameTable)/sizeof(status_entry);
367 
368    while(i>0)
369    {
370       i--;
371       if (sNameTable[i].code == PHNFCSTATUS(status))
372       {
373          return sNameTable[i].name;
374       }
375    }
376 
377    return "UNKNOWN";
378 }
379 
addTechIfNeeded(int * techList,int * handleList,int * typeList,int listSize,int maxListSize,int techToAdd,int handleToAdd,int typeToAdd)380 int addTechIfNeeded(int *techList, int* handleList, int* typeList, int listSize,
381         int maxListSize, int techToAdd, int handleToAdd, int typeToAdd) {
382     bool found = false;
383     for (int i = 0; i < listSize; i++) {
384         if (techList[i] == techToAdd) {
385             found = true;
386             break;
387         }
388     }
389     if (!found && listSize < maxListSize) {
390         techList[listSize] = techToAdd;
391         handleList[listSize] = handleToAdd;
392         typeList[listSize] = typeToAdd;
393         return listSize + 1;
394     }
395     else {
396         return listSize;
397     }
398 }
399 
400 
401 #define MAX_NUM_TECHNOLOGIES 32
402 
403 /*
404  *  Utility to get a technology tree and a corresponding handle list from a detected tag.
405  */
nfc_jni_get_technology_tree(JNIEnv * e,phLibNfc_RemoteDevList_t * devList,uint8_t count,ScopedLocalRef<jintArray> * techList,ScopedLocalRef<jintArray> * handleList,ScopedLocalRef<jintArray> * libnfcTypeList)406 void nfc_jni_get_technology_tree(JNIEnv* e, phLibNfc_RemoteDevList_t* devList, uint8_t count,
407                                  ScopedLocalRef<jintArray>* techList,
408                                  ScopedLocalRef<jintArray>* handleList,
409                                  ScopedLocalRef<jintArray>* libnfcTypeList)
410 {
411    int technologies[MAX_NUM_TECHNOLOGIES];
412    int handles[MAX_NUM_TECHNOLOGIES];
413    int libnfctypes[MAX_NUM_TECHNOLOGIES];
414 
415    int index = 0;
416    // TODO: This counts from up to down because on multi-protocols, the
417    // ISO handle is usually the second, and we prefer the ISO. Should implement
418    // a method to find the "preferred handle order" and use that instead,
419    // since we shouldn't have dependencies on the tech list ordering.
420    for (int target = count - 1; target >= 0; target--) {
421        int type = devList[target].psRemoteDevInfo->RemDevType;
422        int handle = devList[target].hTargetDev;
423        switch (type)
424        {
425           case phNfc_eISO14443_A_PICC:
426           case phNfc_eISO14443_4A_PICC:
427             {
428               index = addTechIfNeeded(technologies, handles, libnfctypes, index,
429                       MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type);
430               break;
431             }
432           case phNfc_eISO14443_4B_PICC:
433             {
434               index = addTechIfNeeded(technologies, handles, libnfctypes, index,
435                       MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type);
436               index = addTechIfNeeded(technologies, handles, libnfctypes, index,
437                       MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3B, handle, type);
438             }break;
439           case phNfc_eISO14443_3A_PICC:
440             {
441               index = addTechIfNeeded(technologies, handles, libnfctypes,
442                       index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3A, handle, type);
443             }break;
444           case phNfc_eISO14443_B_PICC:
445             {
446               // TODO a bug in libnfc will cause 14443-3B only cards
447               // to be returned as this type as well, but these cards
448               // are very rare. Hence assume it's -4B
449               index = addTechIfNeeded(technologies, handles, libnfctypes,
450                       index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type);
451               index = addTechIfNeeded(technologies, handles, libnfctypes,
452                       index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3B, handle, type);
453             }break;
454           case phNfc_eISO15693_PICC:
455             {
456               index = addTechIfNeeded(technologies, handles, libnfctypes,
457                       index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO15693, handle, type);
458             }break;
459           case phNfc_eMifare_PICC:
460             {
461               // We don't want to be too clever here; libnfc has already determined
462               // it's a Mifare, so we only check for UL, for all other tags
463               // we assume it's a mifare classic. This should make us more
464               // future-proof.
465               int sak = devList[target].psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak;
466               switch(sak)
467               {
468                 case 0x00:
469                   // could be UL or UL-C
470                   index = addTechIfNeeded(technologies, handles, libnfctypes,
471                           index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_MIFARE_UL, handle, type);
472                   break;
473                 default:
474                   index = addTechIfNeeded(technologies, handles, libnfctypes,
475                           index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_MIFARE_CLASSIC, handle, type);
476                   break;
477               }
478             }break;
479           case phNfc_eFelica_PICC:
480             {
481               index = addTechIfNeeded(technologies, handles, libnfctypes,
482                       index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_FELICA, handle, type);
483             }break;
484           case phNfc_eJewel_PICC:
485             {
486               // Jewel represented as NfcA
487               index = addTechIfNeeded(technologies, handles, libnfctypes,
488                       index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3A, handle, type);
489             }break;
490           default:
491             {
492               index = addTechIfNeeded(technologies, handles, libnfctypes,
493                       index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_UNKNOWN, handle, type);
494             }
495         }
496    }
497 
498    // Build the Java arrays
499    if (techList != NULL) {
500        techList->reset(e->NewIntArray(index));
501        e->SetIntArrayRegion(techList->get(), 0, index, technologies);
502    }
503 
504    if (handleList != NULL) {
505        handleList->reset(e->NewIntArray(index));
506        e->SetIntArrayRegion(handleList->get(), 0, index, handles);
507    }
508 
509    if (libnfcTypeList != NULL) {
510        libnfcTypeList->reset(e->NewIntArray(index));
511        e->SetIntArrayRegion(libnfcTypeList->get(), 0, index, libnfctypes);
512    }
513 }
514 
515 } // namespace android
516