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