| /* |
| * Copyright (C) 2010 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "errno.h" |
| #include "com_android_nfc.h" |
| #include "com_android_nfc_list.h" |
| #include "phLibNfcStatus.h" |
| |
| /* |
| * JNI Initialization |
| */ |
| jint JNI_OnLoad(JavaVM *jvm, void *reserved) |
| { |
| JNIEnv *e; |
| |
| LOGD("NFC Service : loading JNI\n"); |
| |
| // Check JNI version |
| if(jvm->GetEnv((void **)&e, JNI_VERSION_1_6)) |
| return JNI_ERR; |
| |
| if (android::register_com_android_nfc_NativeNfcManager(e) == -1) |
| return JNI_ERR; |
| if (android::register_com_android_nfc_NativeNfcTag(e) == -1) |
| return JNI_ERR; |
| if (android::register_com_android_nfc_NativeP2pDevice(e) == -1) |
| return JNI_ERR; |
| if (android::register_com_android_nfc_NativeLlcpSocket(e) == -1) |
| return JNI_ERR; |
| if (android::register_com_android_nfc_NativeLlcpConnectionlessSocket(e) == -1) |
| return JNI_ERR; |
| if (android::register_com_android_nfc_NativeLlcpServiceSocket(e) == -1) |
| return JNI_ERR; |
| if (android::register_com_android_nfc_NativeNfcSecureElement(e) == -1) |
| return JNI_ERR; |
| |
| return JNI_VERSION_1_6; |
| } |
| |
| namespace android { |
| |
| extern struct nfc_jni_native_data *exported_nat; |
| |
| /* |
| * JNI Utils |
| */ |
| bool nfc_cb_data_init(nfc_jni_callback_data* pCallbackData, void* pContext) |
| { |
| /* Create semaphore */ |
| if(sem_init(&pCallbackData->sem, 0, 0) == -1) |
| { |
| LOGE("Semaphore creation failed (errno=0x%08x)", errno); |
| return false; |
| } |
| |
| /* Set default status value */ |
| pCallbackData->status = NFCSTATUS_FAILED; |
| |
| /* Copy the context */ |
| pCallbackData->pContext = pContext; |
| |
| /* Add to active semaphore list */ |
| if (!listAdd(&nfc_jni_get_monitor()->sem_list, pCallbackData)) |
| { |
| LOGE("Failed to add the semaphore to the list"); |
| } |
| |
| return true; |
| } |
| |
| void nfc_cb_data_deinit(nfc_jni_callback_data* pCallbackData) |
| { |
| /* Destroy semaphore */ |
| if (sem_destroy(&pCallbackData->sem)) |
| { |
| LOGE("Failed to destroy semaphore (errno=0x%08x)", errno); |
| } |
| |
| /* Remove from active semaphore list */ |
| if (!listRemove(&nfc_jni_get_monitor()->sem_list, pCallbackData)) |
| { |
| LOGE("Failed to remove semaphore from the list"); |
| } |
| |
| } |
| |
| void nfc_cb_data_releaseAll() |
| { |
| nfc_jni_callback_data* pCallbackData; |
| |
| while (listGetAndRemoveNext(&nfc_jni_get_monitor()->sem_list, (void**)&pCallbackData)) |
| { |
| pCallbackData->status = NFCSTATUS_FAILED; |
| sem_post(&pCallbackData->sem); |
| } |
| } |
| |
| int nfc_jni_cache_object(JNIEnv *e, const char *clsname, |
| jobject *cached_obj) |
| { |
| jclass cls; |
| jobject obj; |
| jmethodID ctor; |
| |
| cls = e->FindClass(clsname); |
| if(cls == NULL) |
| { |
| return -1; |
| LOGD("Find class error\n"); |
| } |
| |
| |
| ctor = e->GetMethodID(cls, "<init>", "()V"); |
| |
| obj = e->NewObject(cls, ctor); |
| if(obj == NULL) |
| { |
| return -1; |
| LOGD("Create object error\n"); |
| } |
| |
| *cached_obj = e->NewGlobalRef(obj); |
| if(*cached_obj == NULL) |
| { |
| e->DeleteLocalRef(obj); |
| LOGD("Global ref error\n"); |
| return -1; |
| } |
| |
| e->DeleteLocalRef(obj); |
| |
| return 0; |
| } |
| |
| |
| struct nfc_jni_native_data* nfc_jni_get_nat(JNIEnv *e, jobject o) |
| { |
| jclass c; |
| jfieldID f; |
| |
| /* Retrieve native structure address */ |
| c = e->GetObjectClass(o); |
| f = e->GetFieldID(c, "mNative", "I"); |
| return (struct nfc_jni_native_data*)e->GetIntField(o, f); |
| } |
| |
| struct nfc_jni_native_data* nfc_jni_get_nat_ext(JNIEnv *e) |
| { |
| return exported_nat; |
| } |
| |
| static nfc_jni_native_monitor_t *nfc_jni_native_monitor = NULL; |
| |
| nfc_jni_native_monitor_t* nfc_jni_init_monitor(void) |
| { |
| |
| pthread_mutexattr_t recursive_attr; |
| |
| pthread_mutexattr_init(&recursive_attr); |
| pthread_mutexattr_settype(&recursive_attr, PTHREAD_MUTEX_RECURSIVE_NP); |
| |
| if(nfc_jni_native_monitor == NULL) |
| { |
| nfc_jni_native_monitor = (nfc_jni_native_monitor_t*)malloc(sizeof(nfc_jni_native_monitor_t)); |
| } |
| |
| if(nfc_jni_native_monitor != NULL) |
| { |
| memset(nfc_jni_native_monitor, 0, sizeof(nfc_jni_native_monitor_t)); |
| |
| if(pthread_mutex_init(&nfc_jni_native_monitor->reentrance_mutex, &recursive_attr) == -1) |
| { |
| LOGE("NFC Manager Reentrance Mutex creation retruned 0x%08x", errno); |
| return NULL; |
| } |
| |
| if(pthread_mutex_init(&nfc_jni_native_monitor->concurrency_mutex, NULL) == -1) |
| { |
| LOGE("NFC Manager Concurrency Mutex creation retruned 0x%08x", errno); |
| return NULL; |
| } |
| |
| if(!listInit(&nfc_jni_native_monitor->sem_list)) |
| { |
| LOGE("NFC Manager Semaphore List creation retruned 0x%08x", errno); |
| return NULL; |
| } |
| } |
| |
| return nfc_jni_native_monitor; |
| } |
| |
| nfc_jni_native_monitor_t* nfc_jni_get_monitor(void) |
| { |
| return nfc_jni_native_monitor; |
| } |
| |
| |
| phLibNfc_Handle nfc_jni_get_p2p_device_handle(JNIEnv *e, jobject o) |
| { |
| jclass c; |
| jfieldID f; |
| |
| c = e->GetObjectClass(o); |
| f = e->GetFieldID(c, "mHandle", "I"); |
| |
| return e->GetIntField(o, f); |
| } |
| |
| jshort nfc_jni_get_p2p_device_mode(JNIEnv *e, jobject o) |
| { |
| jclass c; |
| jfieldID f; |
| |
| c = e->GetObjectClass(o); |
| f = e->GetFieldID(c, "mMode", "S"); |
| |
| return e->GetShortField(o, f); |
| } |
| |
| |
| int nfc_jni_get_connected_tech_index(JNIEnv *e, jobject o) |
| { |
| |
| jclass c; |
| jfieldID f; |
| |
| c = e->GetObjectClass(o); |
| f = e->GetFieldID(c, "mConnectedTechnology", "I"); |
| |
| return e->GetIntField(o, f); |
| |
| } |
| |
| jint nfc_jni_get_connected_technology(JNIEnv *e, jobject o) |
| { |
| jclass c; |
| jfieldID f; |
| int connectedTech = -1; |
| |
| int connectedTechIndex = nfc_jni_get_connected_tech_index(e,o); |
| jintArray techTypes = nfc_jni_get_nfc_tag_type(e, o); |
| |
| if ((connectedTechIndex != -1) && (techTypes != NULL) && |
| (connectedTechIndex < e->GetArrayLength(techTypes))) { |
| jint* technologies = e->GetIntArrayElements(techTypes, 0); |
| if (technologies != NULL) { |
| connectedTech = technologies[connectedTechIndex]; |
| e->ReleaseIntArrayElements(techTypes, technologies, JNI_ABORT); |
| } |
| } |
| |
| return connectedTech; |
| |
| } |
| |
| phLibNfc_Handle nfc_jni_get_connected_handle(JNIEnv *e, jobject o) |
| { |
| jclass c; |
| jfieldID f; |
| phLibNfc_Handle connectedHandle = -1; |
| |
| int connectedTechIndex = nfc_jni_get_connected_tech_index(e,o); |
| c = e->GetObjectClass(o); |
| f = e->GetFieldID(c, "mTechHandles", "[I"); |
| jintArray techHandles = (jintArray) e->GetObjectField(o, f); |
| |
| if ((connectedTechIndex != -1) && (techHandles != NULL) && |
| (connectedTechIndex < e->GetArrayLength(techHandles))) { |
| jint* handles = e->GetIntArrayElements(techHandles, 0); |
| if (handles != NULL) { |
| connectedHandle = handles[connectedTechIndex]; |
| e->ReleaseIntArrayElements(techHandles, handles, JNI_ABORT); |
| } |
| } |
| return connectedHandle; |
| |
| } |
| |
| phLibNfc_Handle nfc_jni_get_nfc_tag_handle(JNIEnv *e, jobject o) |
| { |
| jclass c; |
| jfieldID f; |
| |
| c = e->GetObjectClass(o); |
| f = e->GetFieldID(c, "mHandle", "I"); |
| |
| return e->GetIntField(o, f); |
| } |
| |
| phLibNfc_Handle nfc_jni_get_nfc_socket_handle(JNIEnv *e, jobject o) |
| { |
| jclass c; |
| jfieldID f; |
| |
| c = e->GetObjectClass(o); |
| f = e->GetFieldID(c, "mHandle", "I"); |
| |
| return e->GetIntField(o, f); |
| } |
| |
| jintArray nfc_jni_get_nfc_tag_type(JNIEnv *e, jobject o) |
| { |
| jclass c; |
| jfieldID f; |
| jintArray techtypes; |
| |
| c = e->GetObjectClass(o); |
| f = e->GetFieldID(c, "mTechList","[I"); |
| |
| /* Read the techtypes */ |
| techtypes = (jintArray) e->GetObjectField(o, f); |
| |
| return techtypes; |
| } |
| |
| |
| |
| //Display status code |
| const char* nfc_jni_get_status_name(NFCSTATUS status) |
| { |
| #define STATUS_ENTRY(status) { status, #status } |
| |
| struct status_entry { |
| NFCSTATUS code; |
| const char *name; |
| }; |
| |
| const struct status_entry sNameTable[] = { |
| STATUS_ENTRY(NFCSTATUS_SUCCESS), |
| STATUS_ENTRY(NFCSTATUS_FAILED), |
| STATUS_ENTRY(NFCSTATUS_INVALID_PARAMETER), |
| STATUS_ENTRY(NFCSTATUS_INSUFFICIENT_RESOURCES), |
| STATUS_ENTRY(NFCSTATUS_TARGET_LOST), |
| STATUS_ENTRY(NFCSTATUS_INVALID_HANDLE), |
| STATUS_ENTRY(NFCSTATUS_MULTIPLE_TAGS), |
| STATUS_ENTRY(NFCSTATUS_ALREADY_REGISTERED), |
| STATUS_ENTRY(NFCSTATUS_FEATURE_NOT_SUPPORTED), |
| STATUS_ENTRY(NFCSTATUS_SHUTDOWN), |
| STATUS_ENTRY(NFCSTATUS_ABORTED), |
| STATUS_ENTRY(NFCSTATUS_REJECTED ), |
| STATUS_ENTRY(NFCSTATUS_NOT_INITIALISED), |
| STATUS_ENTRY(NFCSTATUS_PENDING), |
| STATUS_ENTRY(NFCSTATUS_BUFFER_TOO_SMALL), |
| STATUS_ENTRY(NFCSTATUS_ALREADY_INITIALISED), |
| STATUS_ENTRY(NFCSTATUS_BUSY), |
| STATUS_ENTRY(NFCSTATUS_TARGET_NOT_CONNECTED), |
| STATUS_ENTRY(NFCSTATUS_MULTIPLE_PROTOCOLS), |
| STATUS_ENTRY(NFCSTATUS_DESELECTED), |
| STATUS_ENTRY(NFCSTATUS_INVALID_DEVICE), |
| STATUS_ENTRY(NFCSTATUS_MORE_INFORMATION), |
| STATUS_ENTRY(NFCSTATUS_RF_TIMEOUT), |
| STATUS_ENTRY(NFCSTATUS_RF_ERROR), |
| STATUS_ENTRY(NFCSTATUS_BOARD_COMMUNICATION_ERROR), |
| STATUS_ENTRY(NFCSTATUS_INVALID_STATE), |
| STATUS_ENTRY(NFCSTATUS_NOT_REGISTERED), |
| STATUS_ENTRY(NFCSTATUS_RELEASED), |
| STATUS_ENTRY(NFCSTATUS_NOT_ALLOWED), |
| STATUS_ENTRY(NFCSTATUS_INVALID_REMOTE_DEVICE), |
| STATUS_ENTRY(NFCSTATUS_SMART_TAG_FUNC_NOT_SUPPORTED), |
| STATUS_ENTRY(NFCSTATUS_READ_FAILED), |
| STATUS_ENTRY(NFCSTATUS_WRITE_FAILED), |
| STATUS_ENTRY(NFCSTATUS_NO_NDEF_SUPPORT), |
| STATUS_ENTRY(NFCSTATUS_EOF_NDEF_CONTAINER_REACHED), |
| STATUS_ENTRY(NFCSTATUS_INVALID_RECEIVE_LENGTH), |
| STATUS_ENTRY(NFCSTATUS_INVALID_FORMAT), |
| STATUS_ENTRY(NFCSTATUS_INSUFFICIENT_STORAGE), |
| STATUS_ENTRY(NFCSTATUS_FORMAT_ERROR), |
| }; |
| |
| int i = sizeof(sNameTable)/sizeof(status_entry); |
| |
| while(i>0) |
| { |
| i--; |
| if (sNameTable[i].code == PHNFCSTATUS(status)) |
| { |
| return sNameTable[i].name; |
| } |
| } |
| |
| return "UNKNOWN"; |
| } |
| |
| int addTechIfNeeded(int *techList, int* handleList, int listSize, int maxListSize, |
| int techToAdd, int handleToAdd) { |
| bool found = false; |
| for (int i = 0; i < listSize; i++) { |
| if (techList[i] == techToAdd) { |
| found = true; |
| break; |
| } |
| } |
| if (!found && listSize < maxListSize) { |
| techList[listSize] = techToAdd; |
| handleList[listSize] = handleToAdd; |
| return listSize + 1; |
| } |
| else { |
| return listSize; |
| } |
| } |
| |
| |
| #define MAX_NUM_TECHNOLOGIES 32 |
| |
| /* |
| * Utility to get a technology tree and a corresponding handle list from a detected tag. |
| */ |
| void nfc_jni_get_technology_tree(JNIEnv* e, phLibNfc_RemoteDevList_t* devList, |
| uint8_t count, jintArray* techList, jintArray* handleList) |
| { |
| int technologies[MAX_NUM_TECHNOLOGIES]; |
| int handles[MAX_NUM_TECHNOLOGIES]; |
| int index = 0; |
| for (int target = 0; target < count; target++) { |
| int type = devList[target].psRemoteDevInfo->RemDevType; |
| int handle = devList[target].hTargetDev; |
| switch (type) |
| { |
| case phNfc_eISO14443_A_PICC: |
| case phNfc_eISO14443_4A_PICC: |
| { |
| index = addTechIfNeeded(technologies, handles, index, MAX_NUM_TECHNOLOGIES, |
| TARGET_TYPE_ISO14443_4, handle); |
| index = addTechIfNeeded(technologies, handles, index, MAX_NUM_TECHNOLOGIES, |
| TARGET_TYPE_ISO14443_3A, handle); |
| |
| index = addTechIfNeeded(technologies, handles, index, MAX_NUM_TECHNOLOGIES, |
| TARGET_TYPE_NDEF_FORMATABLE, handle); |
| break; |
| } |
| case phNfc_eISO14443_4B_PICC: |
| { |
| index = addTechIfNeeded(technologies, handles, index, MAX_NUM_TECHNOLOGIES, |
| TARGET_TYPE_ISO14443_4, handle); |
| index = addTechIfNeeded(technologies, handles, index, MAX_NUM_TECHNOLOGIES, |
| TARGET_TYPE_ISO14443_3B, handle); |
| }break; |
| case phNfc_eISO14443_3A_PICC: |
| { |
| index = addTechIfNeeded(technologies, handles, index, MAX_NUM_TECHNOLOGIES, |
| TARGET_TYPE_ISO14443_3A, handle); |
| }break; |
| case phNfc_eISO14443_B_PICC: |
| { |
| // TODO a bug in libnfc will cause 14443-3B only cards |
| // to be returned as this type as well, but these cards |
| // are very rare. Hence assume it's -4B |
| index = addTechIfNeeded(technologies, handles, index, MAX_NUM_TECHNOLOGIES, |
| TARGET_TYPE_ISO14443_4, handle); |
| index = addTechIfNeeded(technologies, handles, index, MAX_NUM_TECHNOLOGIES, |
| TARGET_TYPE_ISO14443_3B, handle); |
| }break; |
| case phNfc_eISO15693_PICC: |
| { |
| index = addTechIfNeeded(technologies, handles, index, MAX_NUM_TECHNOLOGIES, |
| TARGET_TYPE_ISO15693, handle); |
| }break; |
| case phNfc_eMifare_PICC: |
| { |
| int sak = devList[target].psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak; |
| switch(sak) |
| { |
| case 0x00: |
| // could be UL or UL-C |
| index = addTechIfNeeded(technologies, handles, index, MAX_NUM_TECHNOLOGIES, |
| TARGET_TYPE_MIFARE_UL, handle); |
| index = addTechIfNeeded(technologies, handles, index, MAX_NUM_TECHNOLOGIES, |
| TARGET_TYPE_ISO14443_3A, handle); |
| index = addTechIfNeeded(technologies, handles, index, MAX_NUM_TECHNOLOGIES, |
| TARGET_TYPE_NDEF_FORMATABLE, handle); |
| break; |
| case 0x08: |
| case 0x09: |
| case 0x10: |
| case 0x11: |
| case 0x18: |
| case 0x28: |
| case 0x38: |
| case 0x88: |
| case 0x98: |
| case 0xB8: |
| index = addTechIfNeeded(technologies, handles, index, MAX_NUM_TECHNOLOGIES, |
| TARGET_TYPE_MIFARE_CLASSIC, handle); |
| index = addTechIfNeeded(technologies, handles, index, MAX_NUM_TECHNOLOGIES, |
| TARGET_TYPE_ISO14443_3A, handle); |
| index = addTechIfNeeded(technologies, handles, index, MAX_NUM_TECHNOLOGIES, |
| TARGET_TYPE_NDEF_FORMATABLE, handle); |
| break; |
| case 0x20: |
| // This could be DESfire, but libnfc returns that as ISO14443_4 |
| // so we shouldn't hit this case |
| default: |
| { |
| index = addTechIfNeeded(technologies, handles, index, MAX_NUM_TECHNOLOGIES, |
| TARGET_TYPE_UNKNOWN, handle); |
| }break; |
| } |
| }break; |
| case phNfc_eFelica_PICC: |
| { |
| index = addTechIfNeeded(technologies, handles, index, MAX_NUM_TECHNOLOGIES, |
| TARGET_TYPE_FELICA, handle); |
| }break; |
| case phNfc_eJewel_PICC: |
| { |
| // TODO expose Jewel in the Java APIs |
| // index = addTechIfNeeded(technologies, handles, index, MAX_NUM_TECHNOLOGIES, |
| // TARGET_TYPE_JEWEL, handle); |
| index = addTechIfNeeded(technologies, handles, index, MAX_NUM_TECHNOLOGIES, |
| TARGET_TYPE_ISO14443_3A, handle); |
| }break; |
| default: |
| { |
| index = addTechIfNeeded(technologies, handles, index, MAX_NUM_TECHNOLOGIES, |
| TARGET_TYPE_UNKNOWN, handle); |
| } |
| } |
| } |
| // Build the Java arrays |
| *techList = e->NewIntArray(index); |
| *handleList = e->NewIntArray(index); |
| |
| jint* techItems = e->GetIntArrayElements(*techList, NULL); |
| jint* handleItems = e->GetIntArrayElements(*handleList, NULL); |
| for (int i = 0; i < index; i++) { |
| techItems[i] = technologies[i]; |
| handleItems[i] = handles[i]; |
| } |
| e->ReleaseIntArrayElements(*techList, techItems, 0); |
| e->ReleaseIntArrayElements(*handleList, handleItems, 0); |
| |
| } |
| |
| } // namespace android |