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