Secure Element Access implementation
Change-Id: Ia1c006c52aaf312408ef2fba96715b1b6c382ea9
diff --git a/jni/Android.mk b/jni/Android.mk
index fb092e5..7119695 100644
--- a/jni/Android.mk
+++ b/jni/Android.mk
@@ -11,6 +11,7 @@
com_android_nfc_NativeNfcManager.cpp \
com_android_nfc_NativeNfcTag.cpp \
com_android_nfc_NativeP2pDevice.cpp \
+ com_android_nfc_NativeNfcSecureElement.cpp \
com_android_nfc.cpp
LOCAL_C_INCLUDES += \
diff --git a/jni/com_android_nfc.cpp b/jni/com_android_nfc.cpp
index 848a678..fa65625 100644
--- a/jni/com_android_nfc.cpp
+++ b/jni/com_android_nfc.cpp
@@ -43,6 +43,8 @@
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;
}
@@ -277,4 +279,81 @@
return "UNKNOWN";
}
+/*
+ * Utility to get target type name from its specs
+ */
+int get_technology_type(phNfc_eRemDevType_t type, uint8_t sak)
+{
+ switch (type)
+ {
+ case phNfc_eISO14443_A_PICC:
+ case phNfc_eISO14443_4A_PICC:
+ case phNfc_eISO14443_4B_PICC:
+ {
+ return TARGET_TYPE_ISO14443_4;
+ }break;
+
+ case phNfc_eISO14443_3A_PICC:
+ {
+ return TARGET_TYPE_ISO14443_3A;
+ }break;
+
+ case phNfc_eISO14443_B_PICC:
+ {
+ /* Actually this can be -3B or -4B
+ * FRI doesn't allow us to tell the diff yet
+ * and the API doesn't know type 4B
+ * so return 3B for now.
+ */
+ return TARGET_TYPE_ISO14443_3B;
+ }break;
+
+ case phNfc_eISO15693_PICC:
+ {
+ return TARGET_TYPE_ISO15693;
+ }break;
+
+ case phNfc_eMifare_PICC:
+ {
+ switch(sak)
+ {
+ case 0x00:
+ // could be UL or UL-C
+ return TARGET_TYPE_MIFARE_UL;
+ case 0x08:
+ case 0x09:
+ case 0x10:
+ case 0x11:
+ case 0x18:
+ case 0x28:
+ case 0x38:
+ case 0x88:
+ case 0x98:
+ case 0xB8:
+ return TARGET_TYPE_MIFARE_CLASSIC;
+ case 0x20:
+ return TARGET_TYPE_MIFARE_DESFIRE;
+ default:
+ {
+ return TARGET_TYPE_UNKNOWN;
+ }break;
+ }
+ }break;
+ case phNfc_eFelica_PICC:
+ {
+ return TARGET_TYPE_FELICA;
+ }break;
+ case phNfc_eJewel_PICC:
+ {
+ return TARGET_TYPE_JEWEL;
+ }break;
+ default:
+ {
+ return TARGET_TYPE_UNKNOWN;
+ }
+ }
+
+ return TARGET_TYPE_UNKNOWN;
+}
+
} // namespace android
diff --git a/jni/com_android_nfc.h b/jni/com_android_nfc.h
index 881c48c..7b27186 100644
--- a/jni/com_android_nfc.h
+++ b/jni/com_android_nfc.h
@@ -152,6 +152,8 @@
nfc_jni_native_monitor_t* nfc_jni_init_monitor(void);
nfc_jni_native_monitor_t* nfc_jni_get_monitor(void);
+int get_technology_type(phNfc_eRemDevType_t type, uint8_t sak);
+
/* P2P */
phLibNfc_Handle nfc_jni_get_p2p_device_handle(JNIEnv *e, jobject o);
jshort nfc_jni_get_p2p_device_mode(JNIEnv *e, jobject o);
@@ -169,6 +171,7 @@
int register_com_android_nfc_NativeLlcpConnectionlessSocket(JNIEnv *e);
int register_com_android_nfc_NativeLlcpServiceSocket(JNIEnv *e);
int register_com_android_nfc_NativeLlcpSocket(JNIEnv *e);
+int register_com_android_nfc_NativeNfcSecureElement(JNIEnv *e);
} // namespace android
diff --git a/jni/com_android_nfc_NativeNfcManager.cpp b/jni/com_android_nfc_NativeNfcManager.cpp
index cd32ede..17a24ab 100644
--- a/jni/com_android_nfc_NativeNfcManager.cpp
+++ b/jni/com_android_nfc_NativeNfcManager.cpp
@@ -26,7 +26,7 @@
#define EEDATA_SETTINGS_NUMBER 22
static phLibNfc_sConfig_t gDrvCfg;
-static void *gHWRef;
+void *gHWRef;
static phNfc_sData_t gInputParam;
static phNfc_sData_t gOutputParam;
@@ -414,83 +414,6 @@
}
}
-/*
- * Utility to get target type name from its specs
- */
-static int get_technology_type(phNfc_eRemDevType_t type, uint8_t sak)
-{
- switch (type)
- {
- case phNfc_eISO14443_A_PICC:
- case phNfc_eISO14443_4A_PICC:
- case phNfc_eISO14443_4B_PICC:
- {
- return TARGET_TYPE_ISO14443_4;
- }break;
-
- case phNfc_eISO14443_3A_PICC:
- {
- return TARGET_TYPE_ISO14443_3A;
- }break;
-
- case phNfc_eISO14443_B_PICC:
- {
- /* Actually this can be -3B or -4B
- * FRI doesn't allow us to tell the diff yet
- * and the API doesn't know type 4B
- * so return 3B for now.
- */
- return TARGET_TYPE_ISO14443_3B;
- }break;
-
- case phNfc_eISO15693_PICC:
- {
- return TARGET_TYPE_ISO15693;
- }break;
-
- case phNfc_eMifare_PICC:
- {
- switch(sak)
- {
- case 0x00:
- // could be UL or UL-C
- return TARGET_TYPE_MIFARE_UL;
- case 0x08:
- case 0x09:
- case 0x10:
- case 0x11:
- case 0x18:
- case 0x28:
- case 0x38:
- case 0x88:
- case 0x98:
- case 0xB8:
- return TARGET_TYPE_MIFARE_CLASSIC;
- case 0x20:
- return TARGET_TYPE_MIFARE_DESFIRE;
- default:
- {
- return TARGET_TYPE_UNKNOWN;
- }break;
- }
- }break;
- case phNfc_eFelica_PICC:
- {
- return TARGET_TYPE_FELICA;
- }break;
- case phNfc_eJewel_PICC:
- {
- return TARGET_TYPE_JEWEL;
- }break;
- default:
- {
- return TARGET_TYPE_UNKNOWN;
- }
- }
-
- return TARGET_TYPE_UNKNOWN;
-}
-
/*
+ * Utility to recover UID from target infos
+ */
diff --git a/jni/com_android_nfc_NativeNfcSecureElement.cpp b/jni/com_android_nfc_NativeNfcSecureElement.cpp
new file mode 100755
index 0000000..ca000c2
--- /dev/null
+++ b/jni/com_android_nfc_NativeNfcSecureElement.cpp
@@ -0,0 +1,533 @@
+/*
+ * 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 <semaphore.h>
+
+#include "com_android_nfc.h"
+
+static sem_t com_android_nfc_jni_secure_element_sem;
+static NFCSTATUS com_android_nfc_jni_cb_status = NFCSTATUS_FAILED;
+static phNfc_sData_t *com_android_nfc_jni_transceive_buffer;
+static phNfc_sData_t *com_android_nfc_jni_ioctl_buffer;
+static phNfc_sRemoteDevInformation_t* SecureElementInfo;
+static int secureElementHandle;
+extern void *gHWRef;
+static int SecureElementTech;
+
+namespace android {
+
+static void com_android_nfc_jni_ioctl_callback ( void* context,
+ phNfc_sData_t* Outparam_Cb,
+ NFCSTATUS status)
+{
+ if (status == NFCSTATUS_SUCCESS )
+ {
+ LOGD("> IOCTL successful");
+ }
+ else
+ {
+ LOGD("> IOCTL error");
+ }
+ com_android_nfc_jni_cb_status = status;
+ com_android_nfc_jni_ioctl_buffer = Outparam_Cb;
+
+ sem_post(&com_android_nfc_jni_secure_element_sem);
+}
+
+static void com_android_nfc_jni_transceive_callback(void *pContext,
+ phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status)
+{
+ LOG_CALLBACK("com_android_nfc_jni_transceive_callback", status);
+
+ com_android_nfc_jni_cb_status = status;
+ com_android_nfc_jni_transceive_buffer = pResBuffer;
+
+ sem_post(&com_android_nfc_jni_secure_element_sem);
+}
+
+
+static void com_android_nfc_jni_connect_callback(void *pContext,
+ phLibNfc_Handle hRemoteDev,
+ phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status)
+{
+ LOG_CALLBACK("com_android_nfc_jni_connect_callback", status);
+
+ com_android_nfc_jni_cb_status = status;
+
+ sem_post(&com_android_nfc_jni_secure_element_sem);
+}
+
+static void com_android_nfc_jni_disconnect_callback(void *pContext,
+ phLibNfc_Handle hRemoteDev,
+ NFCSTATUS status)
+{
+ LOG_CALLBACK("com_android_nfc_jni_disconnect_callback", status);
+
+ com_android_nfc_jni_cb_status = status;
+
+ sem_post(&com_android_nfc_jni_secure_element_sem);
+}
+
+/* Set Secure Element mode callback*/
+static void com_android_nfc_jni_smartMX_setModeCb (void* pContext,
+ phLibNfc_Handle hSecureElement,
+ NFCSTATUS status)
+{
+ if(status==NFCSTATUS_SUCCESS)
+ {
+ LOGD("SE Set Mode is Successful");
+ LOGD("SE Handle: %lu", hSecureElement);
+ }
+ else
+ {
+ LOGD("SE Set Mode is failed\n ");
+ }
+
+ com_android_nfc_jni_cb_status = status;
+
+ sem_post(&com_android_nfc_jni_secure_element_sem);
+}
+
+static void com_android_nfc_jni_open_secure_element_notification_callback(void *pContext,
+ phLibNfc_RemoteDevList_t *psRemoteDevList,
+ uint8_t uNofRemoteDev,
+ NFCSTATUS status)
+{
+ JNIEnv *e;
+ NFCSTATUS ret;
+ int i;
+
+ if(status == NFCSTATUS_DESELECTED)
+ {
+ LOG_CALLBACK("com_android_nfc_jni_open_secure_element_notification_callback: Target deselected", status);
+ }
+ else
+ {
+ LOG_CALLBACK("com_android_nfc_jni_open_secure_element_notification_callback", status);
+ LOGI("Discovered %d tags", uNofRemoteDev);
+
+ if(status == NFCSTATUS_MULTIPLE_PROTOCOLS)
+ {
+ LOGD("Multiple Protocol supported\n");
+
+ LOGD("Secure Element Handle: 0x%08x",psRemoteDevList[1].hTargetDev);
+ secureElementHandle = psRemoteDevList[1].hTargetDev;
+
+ /* Set type name */
+ SecureElementTech = get_technology_type(psRemoteDevList[1].psRemoteDevInfo->RemDevType,
+ psRemoteDevList[1].psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak);
+
+ LOGD("Store Secure Element Info\n");
+ SecureElementInfo = psRemoteDevList->psRemoteDevInfo;
+
+ LOGD("Discovered secure element: tech=%d", SecureElementTech);
+ }
+ else
+ {
+ LOGD("Secure Element Handle: 0x%08x",psRemoteDevList->hTargetDev);
+ secureElementHandle = psRemoteDevList->hTargetDev;
+
+ /* Set type name */
+ SecureElementTech = get_technology_type(psRemoteDevList->psRemoteDevInfo->RemDevType,
+ psRemoteDevList->psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak);
+
+ LOGD("Store Secure Element Info\n");
+ SecureElementInfo = psRemoteDevList->psRemoteDevInfo;
+
+ LOGD("Discovered secure element: tech=%d", SecureElementTech);
+ }
+ }
+
+ com_android_nfc_jni_cb_status = status;
+ sem_post(&com_android_nfc_jni_secure_element_sem);
+}
+
+
+static jint com_android_nfc_NativeNfcSecureElement_doOpenSecureElementConnection(JNIEnv *e, jobject o)
+{
+ NFCSTATUS ret;
+ int semResult;
+
+ phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE];
+ uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index=0, SmartMX_detected = 0;
+ phLibNfc_sADD_Cfg_t discovery_cfg;
+ phLibNfc_Registry_Info_t registry_info;
+ phNfc_sData_t InParam;
+ phNfc_sData_t OutParam;
+ uint8_t ExternalRFDetected[3] = {0x00, 0xFC, 0x01};
+ uint8_t Output_Buff[50];
+ uint8_t reg_value;
+ uint8_t mask_value;
+
+ /* Registery */
+ registry_info.MifareUL = TRUE;
+ registry_info.MifareStd = TRUE;
+ registry_info.ISO14443_4A = TRUE;
+ registry_info.ISO14443_4B = TRUE;
+ registry_info.Jewel = TRUE;
+ registry_info.Felica = TRUE;
+ registry_info.NFC = FALSE;
+
+ CONCURRENCY_LOCK();
+
+ LOGD("Open Secure Element");
+
+ /* Test if External RF field is detected */
+ InParam.buffer = ExternalRFDetected;
+ InParam.length = 3;
+ OutParam.buffer = Output_Buff;
+ LOGD("phLibNfc_Mgt_IoCtl()");
+ ret = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_READ,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)e);
+ if(ret!=NFCSTATUS_PENDING)
+ {
+ LOGE("IOCTL status error");
+ }
+ semResult = sem_wait(&com_android_nfc_jni_secure_element_sem);
+ if (semResult)
+ {
+ LOGE("IOCTL semaphore error");
+ goto clean_and_return;
+ }
+
+ if(com_android_nfc_jni_cb_status != NFCSTATUS_SUCCESS)
+ {
+ LOGE("READ MEM ERROR");
+ goto clean_and_return;
+ }
+
+ /* Check the value */
+ reg_value = com_android_nfc_jni_ioctl_buffer->buffer[0];
+ mask_value = reg_value & 0x40;
+
+ if(mask_value == 0x40)
+ {
+ LOGD("External RF Field detected");
+ goto clean_and_return;
+ }
+
+ /* Get Secure Element List */
+ LOGD("phLibNfc_SE_GetSecureElementList()");
+ ret = phLibNfc_SE_GetSecureElementList( SE_List, &No_SE);
+ if (ret == NFCSTATUS_SUCCESS)
+ {
+ LOGD("\n> Number of Secure Element(s) : %d\n", No_SE);
+ /* Display Secure Element information */
+ for (i = 0; i<No_SE; i++)
+ {
+ if (SE_List[i].eSE_Type == phLibNfc_SE_Type_SmartMX)
+ {
+ LOGD("> SMX detected");
+ LOGD("> Secure Element Handle : %d\n", SE_List[i].hSecureElement);
+ /* save SMARTMX index */
+ SmartMX_detected = 1;
+ SmartMX_index = i;
+ }
+ }
+
+ if(SmartMX_detected)
+ {
+ REENTRANCE_LOCK();
+ LOGD("phLibNfc_RemoteDev_NtfRegister()");
+ ret = phLibNfc_RemoteDev_NtfRegister(®istry_info, com_android_nfc_jni_open_secure_element_notification_callback, (void *)e);
+ REENTRANCE_UNLOCK();
+ if(ret != NFCSTATUS_SUCCESS)
+ {
+ LOGW("Register Notification error");
+ goto clean_and_return;
+ }
+
+ /* Set wired mode */
+ REENTRANCE_LOCK();
+ LOGD("phLibNfc_SE_SetMode: Wired mode");
+ ret = phLibNfc_SE_SetMode( SE_List[SmartMX_index].hSecureElement,
+ phLibNfc_SE_ActModeWired,
+ com_android_nfc_jni_smartMX_setModeCb,
+ (void*)e);
+ REENTRANCE_UNLOCK();
+ if (ret != NFCSTATUS_PENDING )
+ {
+ LOGD("\n> SE Set SmartMX mode ERROR \n" );
+ goto clean_and_return;
+ }
+
+ semResult = sem_wait(&com_android_nfc_jni_secure_element_sem);
+ if (semResult)
+ {
+ LOGW("Secure Element opening error");
+ goto clean_and_return;
+ }
+
+ if(com_android_nfc_jni_cb_status != NFCSTATUS_SUCCESS)
+ {
+ LOGE("SE set mode failed");
+ goto clean_and_return;
+ }
+
+ LOGD("Waiting for notification");
+ semResult = sem_wait(&com_android_nfc_jni_secure_element_sem);
+ if (semResult)
+ {
+ LOGW("Secure Element opening error");
+ goto clean_and_return;
+ }
+
+ if(com_android_nfc_jni_cb_status != NFCSTATUS_SUCCESS && com_android_nfc_jni_cb_status != NFCSTATUS_MULTIPLE_PROTOCOLS)
+ {
+ LOGE("SE detection failed");
+ goto clean_and_return;
+ }
+ CONCURRENCY_UNLOCK();
+
+ /* Connect Tag */
+ CONCURRENCY_LOCK();
+ LOGD("phLibNfc_RemoteDev_Connect(SMX)");
+ REENTRANCE_LOCK();
+ ret = phLibNfc_RemoteDev_Connect(secureElementHandle, com_android_nfc_jni_connect_callback,(void *)e);
+ REENTRANCE_UNLOCK();
+ if(ret != NFCSTATUS_PENDING)
+ {
+ LOGE("phLibNfc_RemoteDev_Connect(SMX) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+ goto clean_and_return;
+ }
+ LOGD("phLibNfc_RemoteDev_Connect(SMX) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+
+ /* Wait for callback response */
+ sem_wait(&com_android_nfc_jni_secure_element_sem);
+
+ /* Connect Status */
+ if(com_android_nfc_jni_cb_status != NFCSTATUS_SUCCESS)
+ {
+ goto clean_and_return;
+ }
+
+ CONCURRENCY_UNLOCK();
+ /* Return the Handle of the SecureElement */
+ return secureElementHandle;
+ }
+ else
+ {
+ LOGD("phLibNfc_SE_GetSecureElementList(): No SMX detected");
+ goto clean_and_return;
+ }
+ }
+ else
+ {
+ LOGD("phLibNfc_SE_GetSecureElementList(): Error");
+ goto clean_and_return;
+ }
+
+clean_and_return:
+ CONCURRENCY_UNLOCK();
+ return 0;
+}
+
+
+static jboolean com_android_nfc_NativeNfcSecureElement_doDisconnect(JNIEnv *e, jobject o, jint handle)
+{
+ jclass cls;
+ jfieldID f;
+ NFCSTATUS status;
+ jboolean result = JNI_FALSE;
+ phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE];
+ uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index=0, SmartMX_detected = 0;
+ uint32_t SmartMX_Handle;
+
+ LOGD("Close Secure element function ");
+
+ CONCURRENCY_LOCK();
+ /* Disconnect */
+ LOGI("Disconnecting from SMX (handle = 0x%x)", handle);
+ REENTRANCE_LOCK();
+ status = phLibNfc_RemoteDev_Disconnect(handle,
+ NFC_SMARTMX_RELEASE,
+ com_android_nfc_jni_disconnect_callback,
+ (void *)e);
+ REENTRANCE_UNLOCK();
+ if(status != NFCSTATUS_PENDING)
+ {
+ LOGE("phLibNfc_RemoteDev_Disconnect(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ goto clean_and_return;
+ }
+ LOGD("phLibNfc_RemoteDev_Disconnect(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+
+ /* Wait for callback response */
+ sem_wait(&com_android_nfc_jni_secure_element_sem);
+
+ /* Disconnect Status */
+ if(com_android_nfc_jni_cb_status != NFCSTATUS_SUCCESS)
+ {
+ LOGE("\n> Disconnect SE ERROR \n" );
+ goto clean_and_return;
+ }
+
+ result = JNI_TRUE;
+
+clean_and_return:
+ CONCURRENCY_UNLOCK();
+ return result;
+}
+
+static jbyteArray com_android_nfc_NativeNfcSecureElement_doTransceive(JNIEnv *e,
+ jobject o,jint handle, jbyteArray data)
+{
+ uint8_t offset = 0;
+ uint8_t *buf;
+ uint32_t buflen;
+ phLibNfc_sTransceiveInfo_t transceive_info;
+ jbyteArray result = NULL;
+ int res;
+
+ int tech = SecureElementTech;
+ NFCSTATUS status;
+
+ LOGD("Exchange APDU function ");
+
+ CONCURRENCY_LOCK();
+
+ LOGD("Secure Element tech: %d\n", tech);
+
+ buf = (uint8_t *)e->GetByteArrayElements(data, NULL);
+ buflen = (uint32_t)e->GetArrayLength(data);
+
+ /* Prepare transceive info structure */
+ if(tech == TARGET_TYPE_MIFARE_CLASSIC || tech == TARGET_TYPE_MIFARE_UL)
+ {
+ offset = 2;
+ transceive_info.cmd.MfCmd = (phNfc_eMifareCmdList_t)buf[0];
+ transceive_info.addr = (uint8_t)buf[1];
+ }
+ else if(tech == TARGET_TYPE_ISO14443_4)
+ {
+ transceive_info.cmd.Iso144434Cmd = phNfc_eIso14443_4_Raw;
+ transceive_info.addr = 0;
+ }
+
+ transceive_info.sSendData.buffer = buf + offset;
+ transceive_info.sSendData.length = buflen - offset;
+ transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024);
+ transceive_info.sRecvData.length = 1024;
+
+ if(transceive_info.sRecvData.buffer == NULL)
+ {
+ goto clean_and_return;
+ }
+
+ LOGD("phLibNfc_RemoteDev_Transceive(SMX)");
+ REENTRANCE_LOCK();
+ status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info,
+ com_android_nfc_jni_transceive_callback, (void *)e);
+ REENTRANCE_UNLOCK();
+ if(status != NFCSTATUS_PENDING)
+ {
+ LOGE("phLibNfc_RemoteDev_Transceive(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ goto clean_and_return;
+ }
+ LOGD("phLibNfc_RemoteDev_Transceive(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+
+ /* Wait for callback response */
+ sem_wait(&com_android_nfc_jni_secure_element_sem);
+
+ if(com_android_nfc_jni_cb_status != NFCSTATUS_SUCCESS)
+ {
+ goto clean_and_return;
+ }
+
+ /* Copy results back to Java */
+ result = e->NewByteArray(com_android_nfc_jni_transceive_buffer->length);
+ if(result != NULL)
+ {
+ e->SetByteArrayRegion(result, 0,
+ com_android_nfc_jni_transceive_buffer->length,
+ (jbyte *)com_android_nfc_jni_transceive_buffer->buffer);
+ }
+
+clean_and_return:
+ if(transceive_info.sRecvData.buffer != NULL)
+ {
+ free(transceive_info.sRecvData.buffer);
+ }
+
+ e->ReleaseByteArrayElements(data,
+ (jbyte *)transceive_info.sSendData.buffer, JNI_ABORT);
+
+ CONCURRENCY_UNLOCK();
+
+ return result;
+}
+
+static jbyteArray com_android_nfc_NativeNfcSecureElement_doGetUid(JNIEnv *e, jobject o, jint handle)
+{
+ LOGD("Get Secure element UID function ");
+ jbyteArray SecureElementUid;
+
+ if(handle == secureElementHandle)
+ {
+ SecureElementUid = e->NewByteArray(SecureElementInfo->RemoteDevInfo.Iso14443A_Info.UidLength);
+ e->SetByteArrayRegion(SecureElementUid, 0, SecureElementInfo->RemoteDevInfo.Iso14443A_Info.UidLength,(jbyte *)SecureElementInfo->RemoteDevInfo.Iso14443A_Info.Uid);
+ return SecureElementUid;
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+static jintArray com_android_nfc_NativeNfcSecureElement_doGetTechList(JNIEnv *e, jobject o, jint handle)
+{
+ jintArray techList;
+ LOGD("Get Secure element Type function ");
+
+ if(handle == secureElementHandle)
+ {
+ techList = e->NewIntArray(1);
+ e->SetIntArrayRegion(techList, 0, 1, &SecureElementTech);
+ return techList;
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+
+/*
+ * JNI registration.
+ */
+static JNINativeMethod gMethods[] =
+{
+ {"doOpenSecureElementConnection", "()I",
+ (void *)com_android_nfc_NativeNfcSecureElement_doOpenSecureElementConnection},
+ {"doDisconnect", "(I)Z",
+ (void *)com_android_nfc_NativeNfcSecureElement_doDisconnect},
+ {"doTransceive", "(I[B)[B",
+ (void *)com_android_nfc_NativeNfcSecureElement_doTransceive},
+ {"doGetUid", "(I)[B",
+ (void *)com_android_nfc_NativeNfcSecureElement_doGetUid},
+ {"doGetTechList", "(I)[I",
+ (void *)com_android_nfc_NativeNfcSecureElement_doGetTechList},
+};
+
+int register_com_android_nfc_NativeNfcSecureElement(JNIEnv *e)
+{
+ if(sem_init(&com_android_nfc_jni_secure_element_sem, 0, 0) == -1)
+ return -1;
+
+ return jniRegisterNativeMethods(e,
+ "com/android/nfc/NativeNfcSecureElement",
+ gMethods, NELEM(gMethods));
+}
+
+} // namespace android
diff --git a/src/com/android/nfc/NativeNfcSecureElement.java b/src/com/android/nfc/NativeNfcSecureElement.java
new file mode 100755
index 0000000..b666064
--- /dev/null
+++ b/src/com/android/nfc/NativeNfcSecureElement.java
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+package com.android.nfc;
+
+
+
+/**
+ * Native interface to the NFC Secure Element functions
+ *
+ * {@hide}
+ */
+public class NativeNfcSecureElement {
+
+
+ public NativeNfcSecureElement() {
+ }
+
+ public native int doOpenSecureElementConnection();
+
+ public native boolean doDisconnect(int handle);
+
+ public native byte[] doTransceive(int handle, byte[] data);
+
+ public native int[] doGetTechList(int handle);
+
+ public native byte [] doGetUid(int handle);
+
+}
diff --git a/src/com/android/nfc/NfcService.java b/src/com/android/nfc/NfcService.java
index ce67581..f863176 100755
--- a/src/com/android/nfc/NfcService.java
+++ b/src/com/android/nfc/NfcService.java
@@ -42,6 +42,7 @@
import android.nfc.NdefMessage;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
+import android.nfc.INfcSecureElement;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
@@ -59,6 +60,8 @@
import java.util.HashMap;
import java.util.LinkedList;
import java.util.ListIterator;
+import java.util.Timer;
+import java.util.TimerTask;
public class NfcService extends Application {
static final boolean DBG = false;
@@ -172,6 +175,14 @@
private int mSelectedSeId = 0;
private boolean mNfcSecureElementState;
+ // Secure element
+ private Timer mTimerOpenSmx;
+ private boolean isClosed = false;
+ private boolean isOpened = false;
+ private boolean mOpenSmxPending = false;
+ private NativeNfcSecureElement mSecureElement;
+ private int mSecureElementHandle;
+
// fields below are used in multiple threads and protected by synchronized(this)
private final HashMap<Integer, Object> mObjectMap = new HashMap<Integer, Object>();
private final HashMap<Integer, Object> mSocketMap = new HashMap<Integer, Object>();
@@ -207,6 +218,8 @@
mMyTagServer = new MyTagServer();
mMyTagClient = new MyTagClient(this);
+ mSecureElement = new NativeNfcSecureElement();
+
mPrefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE);
mPrefsEditor = mPrefs.edit();
@@ -597,6 +610,11 @@
return mP2pTargetService;
}
+ public INfcSecureElement getNfcSecureElementInterface() {
+ mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
+ return mSecureElementService;
+ }
+
@Override
public String getProperties(String param) throws RemoteException {
mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
@@ -1744,6 +1762,195 @@
}
};
+ private INfcSecureElement mSecureElementService = new INfcSecureElement.Stub() {
+
+ public int openSecureElementConnection() throws RemoteException {
+ Log.d(TAG, "openSecureElementConnection");
+ int handle;
+
+ // Check if NFC is enabled
+ if (!mIsNfcEnabled) {
+ return 0;
+ }
+
+ // Check in an open is already pending
+ if (mOpenSmxPending) {
+ return 0;
+ }
+
+ handle = mSecureElement.doOpenSecureElementConnection();
+
+ if (handle == 0) {
+ mOpenSmxPending = false;
+ } else {
+ mSecureElementHandle = handle;
+
+ /* Start timer */
+ mTimerOpenSmx = new Timer();
+ mTimerOpenSmx.schedule(new TimerOpenSecureElement(), 30000);
+
+ /* Update state */
+ isOpened = true;
+ isClosed = false;
+ mOpenSmxPending = true;
+ }
+
+ return handle;
+ }
+
+ public int closeSecureElementConnection(int nativeHandle)
+ throws RemoteException {
+
+ // Check if NFC is enabled
+ if (!mIsNfcEnabled) {
+ return ErrorCodes.ERROR_NOT_INITIALIZED;
+ }
+
+ // Check if the SE connection is closed
+ if (isClosed) {
+ return -1;
+ }
+
+ // Check if the SE connection is opened
+ if (!isOpened) {
+ return -1;
+ }
+
+ if (mSecureElement.doDisconnect(nativeHandle)) {
+
+ /* Stop timer */
+ mTimerOpenSmx.cancel();
+
+ /* Restart polling loop for notification */
+ mManager.enableDiscovery(DISCOVERY_MODE_READER);
+
+ /* Update state */
+ isOpened = false;
+ isClosed = true;
+ mOpenSmxPending = false;
+
+ return ErrorCodes.SUCCESS;
+ } else {
+
+ /* Stop timer */
+ mTimerOpenSmx.cancel();
+
+ /* Restart polling loop for notification */
+ mManager.enableDiscovery(DISCOVERY_MODE_READER);
+
+ /* Update state */
+ isOpened = false;
+ isClosed = true;
+ mOpenSmxPending = false;
+
+ return ErrorCodes.ERROR_DISCONNECT;
+ }
+ }
+
+ public int[] getSecureElementTechList(int nativeHandle)
+ throws RemoteException {
+ // Check if NFC is enabled
+ if (!mIsNfcEnabled) {
+ return null;
+ }
+
+ // Check if the SE connection is closed
+ if (isClosed) {
+ return null;
+ }
+
+ // Check if the SE connection is opened
+ if (!isOpened) {
+ return null;
+ }
+
+ int[] techList = mSecureElement.doGetTechList(nativeHandle);
+
+ /* Stop and Restart timer */
+ mTimerOpenSmx.cancel();
+ mTimerOpenSmx = new Timer();
+ mTimerOpenSmx.schedule(new TimerOpenSecureElement(), 30000);
+
+ return techList;
+ }
+
+ public byte[] getSecureElementUid(int nativeHandle)
+ throws RemoteException {
+ byte[] uid;
+
+ // Check if NFC is enabled
+ if (!mIsNfcEnabled) {
+ return null;
+ }
+
+ // Check if the SE connection is closed
+ if (isClosed) {
+ return null;
+ }
+
+ // Check if the SE connection is opened
+ if (!isOpened) {
+ return null;
+ }
+
+ uid = mSecureElement.doGetUid(nativeHandle);
+
+ /* Stop and Restart timer */
+ mTimerOpenSmx.cancel();
+ mTimerOpenSmx = new Timer();
+ mTimerOpenSmx.schedule(new TimerOpenSecureElement(), 30000);
+
+ return uid;
+ }
+
+ public byte[] exchangeAPDU(int nativeHandle, byte[] data)
+ throws RemoteException {
+ byte[] response;
+
+ // Check if NFC is enabled
+ if (!mIsNfcEnabled) {
+ return null;
+ }
+
+ // Check if the SE connection is closed
+ if (isClosed) {
+ return null;
+ }
+
+ // Check if the SE connection is opened
+ if (!isOpened) {
+ return null;
+ }
+
+ response = mSecureElement.doTransceive(nativeHandle, data);
+
+ /* Stop and Restart timer */
+ mTimerOpenSmx.cancel();
+ mTimerOpenSmx = new Timer();
+ mTimerOpenSmx.schedule(new TimerOpenSecureElement(), 30000);
+
+ return response;
+
+ }
+ };
+
+ class TimerOpenSecureElement extends TimerTask {
+
+ @Override
+ public void run() {
+ if (mSecureElementHandle != 0) {
+ Log.d(TAG, "Open SMX timer expired");
+ try {
+ mSecureElementService
+ .closeSecureElementConnection(mSecureElementHandle);
+ } catch (RemoteException e) {
+ }
+ }
+
+ }
+
+ }
+
private boolean _enable(boolean oldEnabledState) {
boolean isSuccess = mManager.initialize();
if (isSuccess) {