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