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
53   return JNI_VERSION_1_6;
54}
55
56namespace android {
57
58extern struct nfc_jni_native_data *exported_nat;
59
60JavaVM *vm;
61
62/*
63 * JNI Utils
64 */
65JNIEnv *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
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      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
100void 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
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   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
153struct 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
161struct nfc_jni_native_data* nfc_jni_get_nat_ext(JNIEnv*)
162{
163   return exported_nat;
164}
165
166static nfc_jni_native_monitor_t *nfc_jni_native_monitor = NULL;
167
168nfc_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
222nfc_jni_native_monitor_t* nfc_jni_get_monitor(void)
223{
224   return nfc_jni_native_monitor;
225}
226
227
228phLibNfc_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
235jshort 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
243int 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
251jint 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
271jint 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
291phLibNfc_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
298phLibNfc_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
305jintArray 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
315const 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
380int 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 */
406void 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