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