diff options
Diffstat (limited to 'nxp/jni/com_android_nfc.cpp')
-rwxr-xr-x | nxp/jni/com_android_nfc.cpp | 576 |
1 files changed, 576 insertions, 0 deletions
diff --git a/nxp/jni/com_android_nfc.cpp b/nxp/jni/com_android_nfc.cpp new file mode 100755 index 0000000..c0e1993 --- /dev/null +++ b/nxp/jni/com_android_nfc.cpp @@ -0,0 +1,576 @@ +/* + * 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 <stdlib.h> + +#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; + + ALOGD("NFC Service : loading JNI\n"); + + // Check JNI version + if(jvm->GetEnv((void **)&e, JNI_VERSION_1_6)) + return JNI_ERR; + + android::vm = jvm; + + 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; + +JavaVM *vm; + +/* + * JNI Utils + */ +JNIEnv *nfc_get_env() +{ + JNIEnv *e; + if (vm->GetEnv((void **)&e, JNI_VERSION_1_6) != JNI_OK) { + ALOGE("Current thread is not attached to VM"); + phLibNfc_Mgt_Recovery(); + abort(); + } + return e; +} + +bool nfc_cb_data_init(nfc_jni_callback_data* pCallbackData, void* pContext) +{ + /* Create semaphore */ + if(sem_init(&pCallbackData->sem, 0, 0) == -1) + { + ALOGE("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)) + { + ALOGE("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)) + { + ALOGE("Failed to destroy semaphore (errno=0x%08x)", errno); + } + + /* Remove from active semaphore list */ + if (!listRemove(&nfc_jni_get_monitor()->sem_list, pCallbackData)) + { + ALOGE("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; + ALOGD("Find class error\n"); + } + + + ctor = e->GetMethodID(cls, "<init>", "()V"); + + obj = e->NewObject(cls, ctor); + if(obj == NULL) + { + return -1; + ALOGD("Create object error\n"); + } + + *cached_obj = e->NewGlobalRef(obj); + if(*cached_obj == NULL) + { + e->DeleteLocalRef(obj); + ALOGD("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) + { + ALOGE("NFC Manager Reentrance Mutex creation returned 0x%08x", errno); + return NULL; + } + + if(pthread_mutex_init(&nfc_jni_native_monitor->concurrency_mutex, NULL) == -1) + { + ALOGE("NFC Manager Concurrency Mutex creation returned 0x%08x", errno); + return NULL; + } + + if(!listInit(&nfc_jni_native_monitor->sem_list)) + { + ALOGE("NFC Manager Semaphore List creation failed"); + return NULL; + } + + LIST_INIT(&nfc_jni_native_monitor->incoming_socket_head); + + if(pthread_mutex_init(&nfc_jni_native_monitor->incoming_socket_mutex, NULL) == -1) + { + ALOGE("NFC Manager incoming socket mutex creation returned 0x%08x", errno); + return NULL; + } + + if(pthread_cond_init(&nfc_jni_native_monitor->incoming_socket_cond, NULL) == -1) + { + ALOGE("NFC Manager incoming socket condition creation returned 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, "mConnectedTechIndex", "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; + +} + +jint nfc_jni_get_connected_technology_libnfc_type(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + jint connectedLibNfcType = -1; + + int connectedTechIndex = nfc_jni_get_connected_tech_index(e,o); + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mTechLibNfcTypes", "[I"); + jintArray libNfcTypes = (jintArray) e->GetObjectField(o, f); + + if ((connectedTechIndex != -1) && (libNfcTypes != NULL) && + (connectedTechIndex < e->GetArrayLength(libNfcTypes))) { + jint* types = e->GetIntArrayElements(libNfcTypes, 0); + if (types != NULL) { + connectedLibNfcType = types[connectedTechIndex]; + e->ReleaseIntArrayElements(libNfcTypes, types, JNI_ABORT); + } + } + return connectedLibNfcType; + +} + +phLibNfc_Handle nfc_jni_get_connected_handle(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mConnectedHandle", "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* typeList, int listSize, + int maxListSize, int techToAdd, int handleToAdd, int typeToAdd) { + 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; + typeList[listSize] = typeToAdd; + 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, + jintArray* libnfcTypeList) +{ + int technologies[MAX_NUM_TECHNOLOGIES]; + int handles[MAX_NUM_TECHNOLOGIES]; + int libnfctypes[MAX_NUM_TECHNOLOGIES]; + + int index = 0; + // TODO: This counts from up to down because on multi-protocols, the + // ISO handle is usually the second, and we prefer the ISO. Should implement + // a method to find the "preferred handle order" and use that instead, + // since we shouldn't have dependencies on the tech list ordering. + for (int target = count - 1; target >= 0; target--) { + int type = devList[target].psRemoteDevInfo->RemDevType; + int handle = devList[target].hTargetDev; + switch (type) + { + case phNfc_eISO14443_A_PCD: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, index, + MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4A_PCD, handle, type); + break; + } + case phNfc_eISO14443_B_PCD: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, index, + MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4B_PCD, handle, type); + break; + } + case phNfc_eISO14443_A_PICC: + case phNfc_eISO14443_4A_PICC: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, index, + MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type); + break; + } + case phNfc_eISO14443_4B_PICC: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, index, + MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type); + index = addTechIfNeeded(technologies, handles, libnfctypes, index, + MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3B, handle, type); + }break; + case phNfc_eISO14443_3A_PICC: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3A, handle, type); + }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, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type); + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3B, handle, type); + }break; + case phNfc_eISO15693_PICC: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO15693, handle, type); + }break; + case phNfc_eMifare_PICC: + { + // We don't want to be too clever here; libnfc has already determined + // it's a Mifare, so we only check for UL, for all other tags + // we assume it's a mifare classic. This should make us more + // future-proof. + int sak = devList[target].psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak; + switch(sak) + { + case 0x00: + // could be UL or UL-C + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_MIFARE_UL, handle, type); + break; + default: + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_MIFARE_CLASSIC, handle, type); + break; + } + }break; + case phNfc_eFelica_PICC: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_FELICA, handle, type); + }break; + case phNfc_eJewel_PICC: + { + // Jewel represented as NfcA + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3A, handle, type); + }break; + default: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_UNKNOWN, handle, type); + } + } + } + + // Build the Java arrays + if (techList != NULL) { + *techList = e->NewIntArray(index); + e->SetIntArrayRegion(*techList, 0, index, technologies); + } + + if (handleList != NULL) { + *handleList = e->NewIntArray(index); + e->SetIntArrayRegion(*handleList, 0, index, handles); + } + + if (libnfcTypeList != NULL) { + *libnfcTypeList = e->NewIntArray(index); + e->SetIntArrayRegion(*libnfcTypeList, 0, index, libnfctypes); + } +} + +} // namespace android |