summaryrefslogtreecommitdiffstats
path: root/nci/jni
diff options
context:
space:
mode:
Diffstat (limited to 'nci/jni')
-rw-r--r--nci/jni/Android.mk54
-rw-r--r--nci/jni/CondVar.cpp145
-rw-r--r--nci/jni/CondVar.h91
-rw-r--r--nci/jni/DataQueue.cpp155
-rw-r--r--nci/jni/DataQueue.h106
-rw-r--r--nci/jni/HostAidRouter.cpp291
-rw-r--r--nci/jni/HostAidRouter.h156
-rw-r--r--nci/jni/IntervalTimer.cpp99
-rw-r--r--nci/jni/IntervalTimer.h38
-rw-r--r--nci/jni/JavaClassConstants.h37
-rw-r--r--nci/jni/Mutex.cpp136
-rw-r--r--nci/jni/Mutex.h113
-rw-r--r--nci/jni/NativeLlcpConnectionlessSocket.cpp311
-rw-r--r--nci/jni/NativeLlcpServiceSocket.cpp158
-rw-r--r--nci/jni/NativeLlcpSocket.cpp271
-rwxr-xr-xnci/jni/NativeNfcManager.cpp1816
-rwxr-xr-xnci/jni/NativeNfcTag.cpp1507
-rw-r--r--nci/jni/NativeP2pDevice.cpp93
-rwxr-xr-xnci/jni/NativeSecureElement.cpp245
-rwxr-xr-xnci/jni/NfcJniUtil.cpp150
-rwxr-xr-xnci/jni/NfcJniUtil.h152
-rwxr-xr-xnci/jni/NfcTag.cpp1325
-rwxr-xr-xnci/jni/NfcTag.h419
-rw-r--r--nci/jni/PeerToPeer.cpp1840
-rw-r--r--nci/jni/PeerToPeer.h779
-rw-r--r--nci/jni/Pn544Interop.cpp153
-rw-r--r--nci/jni/Pn544Interop.h64
-rwxr-xr-xnci/jni/PowerSwitch.cpp439
-rwxr-xr-xnci/jni/PowerSwitch.h258
-rw-r--r--nci/jni/RouteDataSet.cpp555
-rw-r--r--nci/jni/RouteDataSet.h308
-rwxr-xr-xnci/jni/SecureElement.cpp2189
-rwxr-xr-xnci/jni/SecureElement.h607
-rw-r--r--nci/jni/SyncEvent.h171
34 files changed, 15231 insertions, 0 deletions
diff --git a/nci/jni/Android.mk b/nci/jni/Android.mk
new file mode 100644
index 0000000..39832fd
--- /dev/null
+++ b/nci/jni/Android.mk
@@ -0,0 +1,54 @@
+VOB_COMPONENTS := external/libnfc-nci/src
+NFA := $(VOB_COMPONENTS)/nfa
+NFC := $(VOB_COMPONENTS)/nfc
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+LOCAL_PRELINK_MODULE := false
+
+ifneq ($(NCI_VERSION),)
+LOCAL_CFLAGS += -DNCI_VERSION=$(NCI_VERSION) -O0 -g
+endif
+
+define all-cpp-files-under
+$(patsubst ./%,%, \
+ $(shell cd $(LOCAL_PATH) ; \
+ find $(1) -name "*.cpp" -and -not -name ".*") \
+ )
+endef
+
+LOCAL_SRC_FILES:= $(call all-cpp-files-under, .)
+
+LOCAL_C_INCLUDES += \
+ bionic \
+ bionic/libstdc++ \
+ external/stlport/stlport \
+ external/libxml2/include \
+ external/icu4c/common \
+ frameworks/native/include \
+ $(NFA)/include \
+ $(NFA)/brcm \
+ $(NFC)/include \
+ $(NFC)/brcm \
+ $(NFC)/int \
+ $(VOB_COMPONENTS)/hal/include \
+ $(VOB_COMPONENTS)/hal/int \
+ $(VOB_COMPONENTS)/include \
+ $(VOB_COMPONENTS)/gki/ulinux \
+ $(VOB_COMPONENTS)/gki/common
+
+LOCAL_SHARED_LIBRARIES := \
+ libicuuc \
+ libnativehelper \
+ libcutils \
+ libutils \
+ libnfc-nci \
+ libstlport
+
+LOCAL_STATIC_LIBRARIES := libxml2
+
+LOCAL_MODULE := libnfc_nci_jni
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
+
diff --git a/nci/jni/CondVar.cpp b/nci/jni/CondVar.cpp
new file mode 100644
index 0000000..e69cc46
--- /dev/null
+++ b/nci/jni/CondVar.cpp
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+/*
+ * Encapsulate a condition variable for thread synchronization.
+ */
+
+#include "CondVar.h"
+#include "NfcJniUtil.h"
+#include <errno.h>
+
+
+/*******************************************************************************
+**
+** Function: CondVar
+**
+** Description: Initialize member variables.
+**
+** Returns: None.
+**
+*******************************************************************************/
+CondVar::CondVar ()
+{
+ memset (&mCondition, 0, sizeof(mCondition));
+ int const res = pthread_cond_init (&mCondition, NULL);
+ if (res)
+ {
+ ALOGE ("CondVar::CondVar: fail init; error=0x%X", res);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: ~CondVar
+**
+** Description: Cleanup all resources.
+**
+** Returns: None.
+**
+*******************************************************************************/
+CondVar::~CondVar ()
+{
+ int const res = pthread_cond_destroy (&mCondition);
+ if (res)
+ {
+ ALOGE ("CondVar::~CondVar: fail destroy; error=0x%X", res);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: wait
+**
+** Description: Block the caller and wait for a condition.
+**
+** Returns: None.
+**
+*******************************************************************************/
+void CondVar::wait (Mutex& mutex)
+{
+ int const res = pthread_cond_wait (&mCondition, mutex.nativeHandle());
+ if (res)
+ {
+ ALOGE ("CondVar::wait: fail wait; error=0x%X", res);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: wait
+**
+** Description: Block the caller and wait for a condition.
+** millisec: Timeout in milliseconds.
+**
+** Returns: True if wait is successful; false if timeout occurs.
+**
+*******************************************************************************/
+bool CondVar::wait (Mutex& mutex, long millisec)
+{
+ bool retVal = false;
+ struct timespec absoluteTime;
+
+ if (clock_gettime (CLOCK_MONOTONIC, &absoluteTime) == -1)
+ {
+ ALOGE ("CondVar::wait: fail get time; errno=0x%X", errno);
+ }
+ else
+ {
+ absoluteTime.tv_sec += millisec / 1000;
+ long ns = absoluteTime.tv_nsec + ((millisec % 1000) * 1000000);
+ if (ns > 1000000000)
+ {
+ absoluteTime.tv_sec++;
+ absoluteTime.tv_nsec = ns - 1000000000;
+ }
+ else
+ absoluteTime.tv_nsec = ns;
+ }
+
+ //pthread_cond_timedwait_monotonic_np() is an Android-specific function
+ //declared in /development/ndk/platforms/android-9/include/pthread.h;
+ //it uses monotonic clock.
+ //the standard pthread_cond_timedwait() uses realtime clock.
+ int waitResult = pthread_cond_timedwait_monotonic_np (&mCondition, mutex.nativeHandle(), &absoluteTime);
+ if ((waitResult != 0) && (waitResult != ETIMEDOUT))
+ ALOGE ("CondVar::wait: fail timed wait; error=0x%X", waitResult);
+ retVal = (waitResult == 0); //waited successfully
+ return retVal;
+}
+
+
+/*******************************************************************************
+**
+** Function: notifyOne
+**
+** Description: Unblock the waiting thread.
+**
+** Returns: None.
+**
+*******************************************************************************/
+void CondVar::notifyOne ()
+{
+ int const res = pthread_cond_signal (&mCondition);
+ if (res)
+ {
+ ALOGE ("CondVar::notifyOne: fail signal; error=0x%X", res);
+ }
+}
+
diff --git a/nci/jni/CondVar.h b/nci/jni/CondVar.h
new file mode 100644
index 0000000..c286d5c
--- /dev/null
+++ b/nci/jni/CondVar.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+/*
+ * Encapsulate a condition variable for thread synchronization.
+ */
+
+#pragma once
+#include <pthread.h>
+#include "Mutex.h"
+
+
+class CondVar
+{
+public:
+ /*******************************************************************************
+ **
+ ** Function: CondVar
+ **
+ ** Description: Initialize member variables.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ CondVar ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: ~CondVar
+ **
+ ** Description: Cleanup all resources.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ ~CondVar ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: wait
+ **
+ ** Description: Block the caller and wait for a condition.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ void wait (Mutex& mutex);
+
+
+ /*******************************************************************************
+ **
+ ** Function: wait
+ **
+ ** Description: Block the caller and wait for a condition.
+ ** millisec: Timeout in milliseconds.
+ **
+ ** Returns: True if wait is successful; false if timeout occurs.
+ **
+ *******************************************************************************/
+ bool wait (Mutex& mutex, long millisec);
+
+
+ /*******************************************************************************
+ **
+ ** Function: notifyOne
+ **
+ ** Description: Unblock the waiting thread.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ void notifyOne ();
+
+private:
+ pthread_cond_t mCondition;
+};
diff --git a/nci/jni/DataQueue.cpp b/nci/jni/DataQueue.cpp
new file mode 100644
index 0000000..caa2575
--- /dev/null
+++ b/nci/jni/DataQueue.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+/*
+ * Store data bytes in a variable-size queue.
+ */
+
+#include "DataQueue.h"
+
+
+/*******************************************************************************
+**
+** Function: DataQueue
+**
+** Description: Initialize member variables.
+**
+** Returns: None.
+**
+*******************************************************************************/
+DataQueue::DataQueue ()
+{
+}
+
+
+/*******************************************************************************
+**
+** Function: ~DataQueue
+**
+** Description: Release all resources.
+**
+** Returns: None.
+**
+*******************************************************************************/
+DataQueue::~DataQueue ()
+{
+ mMutex.lock ();
+ while (mQueue.empty() == false)
+ {
+ tHeader* header = mQueue.front ();
+ mQueue.pop_front ();
+ free (header);
+ }
+ mMutex.unlock ();
+}
+
+
+bool DataQueue::isEmpty()
+{
+ mMutex.lock ();
+ bool retval = mQueue.empty();
+ mMutex.unlock ();
+ return retval;
+}
+
+
+/*******************************************************************************
+**
+** Function: enqueue
+**
+** Description: Append data to the queue.
+** data: array of bytes
+** dataLen: length of the data.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool DataQueue::enqueue (UINT8* data, UINT16 dataLen)
+{
+ if ((data == NULL) || (dataLen==0))
+ return false;
+
+ mMutex.lock ();
+
+ bool retval = false;
+ tHeader* header = (tHeader*) malloc (sizeof(tHeader) + dataLen);
+
+ if (header)
+ {
+ memset (header, 0, sizeof(tHeader));
+ header->mDataLen = dataLen;
+ memcpy (header+1, data, dataLen);
+
+ mQueue.push_back (header);
+
+ retval = true;
+ }
+ else
+ {
+ ALOGE ("DataQueue::enqueue: out of memory ?????");
+ }
+ mMutex.unlock ();
+ return retval;
+}
+
+
+/*******************************************************************************
+**
+** Function: dequeue
+**
+** Description: Retrieve and remove data from the front of the queue.
+** buffer: array to store the data.
+** bufferMaxLen: maximum size of the buffer.
+** actualLen: actual length of the data.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool DataQueue::dequeue (UINT8* buffer, UINT16 bufferMaxLen, UINT16& actualLen)
+{
+ mMutex.lock ();
+
+ tHeader* header = mQueue.front ();
+ bool retval = false;
+
+ if (header && buffer && (bufferMaxLen>0))
+ {
+ if (header->mDataLen <= bufferMaxLen)
+ {
+ //caller's buffer is big enough to store all data
+ actualLen = header->mDataLen;
+ char* src = (char*)(header) + sizeof(tHeader) + header->mOffset;
+ memcpy (buffer, src, actualLen);
+
+ mQueue.pop_front ();
+ free (header);
+ }
+ else
+ {
+ //caller's buffer is too small
+ actualLen = bufferMaxLen;
+ char* src = (char*)(header) + sizeof(tHeader) + header->mOffset;
+ memcpy (buffer, src, actualLen);
+ //adjust offset so the next dequeue() will get the remainder
+ header->mDataLen -= actualLen;
+ header->mOffset += actualLen;
+ }
+ retval = true;
+ }
+ mMutex.unlock ();
+ return retval;
+}
+
diff --git a/nci/jni/DataQueue.h b/nci/jni/DataQueue.h
new file mode 100644
index 0000000..bfd415c
--- /dev/null
+++ b/nci/jni/DataQueue.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+/*
+ * Store data bytes in a variable-size queue.
+ */
+
+#pragma once
+#include "NfcJniUtil.h"
+#include "gki.h"
+#include "Mutex.h"
+#include <list>
+
+
+class DataQueue
+{
+public:
+ /*******************************************************************************
+ **
+ ** Function: DataQueue
+ **
+ ** Description: Initialize member variables.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ DataQueue ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: ~DataQueue
+ **
+ ** Description: Release all resources.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ ~DataQueue ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: enqueue
+ **
+ ** Description: Append data to the queue.
+ ** data: array of bytes
+ ** dataLen: length of the data.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool enqueue (UINT8* data, UINT16 dataLen);
+
+
+ /*******************************************************************************
+ **
+ ** Function: dequeue
+ **
+ ** Description: Retrieve and remove data from the front of the queue.
+ ** buffer: array to store the data.
+ ** bufferMaxLen: maximum size of the buffer.
+ ** actualLen: actual length of the data.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool dequeue (UINT8* buffer, UINT16 bufferMaxLen, UINT16& actualLen);
+
+
+ /*******************************************************************************
+ **
+ ** Function: isEmpty
+ **
+ ** Description: Whether the queue is empty.
+ **
+ ** Returns: True if empty.
+ **
+ *******************************************************************************/
+ bool isEmpty();
+
+private:
+ struct tHeader
+ {
+ UINT16 mDataLen; //number of octets of data
+ UINT16 mOffset; //offset of the first octet of data
+ };
+ typedef std::list<tHeader*> Queue;
+
+ Queue mQueue;
+ Mutex mMutex;
+};
+
diff --git a/nci/jni/HostAidRouter.cpp b/nci/jni/HostAidRouter.cpp
new file mode 100644
index 0000000..0b511f8
--- /dev/null
+++ b/nci/jni/HostAidRouter.cpp
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+/*
+ * Manage listen-mode AID routing to the host.
+ */
+#include "OverrideLog.h"
+#include "HostAidRouter.h"
+#include "config.h"
+#include "SecureElement.h"
+
+
+HostAidRouter HostAidRouter::sHostAidRouter; //singleton HostAidRouter object
+
+
+/*******************************************************************************
+**
+** Function: HostAidRouter
+**
+** Description: Private constructor to prevent public call.
+**
+** Returns: None.
+**
+*******************************************************************************/
+HostAidRouter::HostAidRouter ()
+ : mTempHandle (NFA_HANDLE_INVALID),
+ mIsFeatureEnabled (true)
+{
+}
+
+
+/*******************************************************************************
+**
+** Function: ~HostAidRouter
+**
+** Description: Private destructor to prevent public call.
+**
+** Returns: None.
+**
+*******************************************************************************/
+HostAidRouter::~HostAidRouter ()
+{
+}
+
+
+/*******************************************************************************
+**
+** Function: getInstance
+**
+** Description: Obtain a reference to the singleton object of HostAidRouter
+**
+** Returns: Reference to HostAidRouter object.
+**
+*******************************************************************************/
+HostAidRouter& HostAidRouter::getInstance ()
+{
+ return sHostAidRouter;
+}
+
+
+/*******************************************************************************
+**
+** Function: initialize
+**
+** Description: Initialize all resources.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool HostAidRouter::initialize ()
+{
+ unsigned long num = 0;
+ mTempHandle = NFA_HANDLE_INVALID;
+ mHandleDatabase.clear ();
+
+ if (GetNumValue (NAME_REGISTER_VIRTUAL_SE, &num, sizeof (num)))
+ mIsFeatureEnabled = num != 0;
+ return true;
+}
+
+
+/*******************************************************************************
+**
+** Function: addPpseRoute
+**
+** Description: Route Proximity Payment System Environment request
+** to the host. This function is called when there is no
+** route data.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool HostAidRouter::addPpseRoute ()
+{
+ static const char fn [] = "HostAidRouter::addPpseRoute";
+ ALOGD ("%s: enter", fn);
+ tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
+ bool retval = false;
+
+ if (! mIsFeatureEnabled)
+ {
+ ALOGD ("%s: feature disabled", fn);
+ goto TheEnd;
+ }
+
+ {
+ ALOGD ("%s: register PPSE AID", fn);
+ SyncEventGuard guard (mRegisterEvent);
+ mTempHandle = NFA_HANDLE_INVALID;
+ nfaStat = NFA_CeRegisterAidOnDH ((UINT8*) "2PAY.SYS.DDF01", 14, stackCallback);
+ if (nfaStat == NFA_STATUS_OK)
+ {
+ mRegisterEvent.wait (); //wait for NFA_CE_REGISTERED_EVT
+ if (mTempHandle == NFA_HANDLE_INVALID)
+ {
+ ALOGE ("%s: received invalid handle", fn);
+ goto TheEnd;
+ }
+ else
+ mHandleDatabase.push_back (mTempHandle);
+ }
+ else
+ {
+ ALOGE ("%s: fail register", fn);
+ goto TheEnd;
+ }
+ }
+ retval = true;
+
+TheEnd:
+ ALOGD ("%s: exit; ok=%u", fn, retval);
+ return retval;
+}
+
+
+/*******************************************************************************
+**
+** Function: deleteAllRoutes
+**
+** Description: Delete all AID routes to the host.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool HostAidRouter::deleteAllRoutes ()
+{
+ static const char fn [] = "HostAidRouter::deleteAllRoutes";
+ ALOGD ("%s: enter", fn);
+ tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
+ bool retval = false;
+
+ if (! mIsFeatureEnabled)
+ {
+ ALOGD ("%s: feature disabled", fn);
+ goto TheEnd;
+ }
+
+ //deregister each registered AID from the stack
+ for (AidHandleDatabase::iterator iter1 = mHandleDatabase.begin(); iter1 != mHandleDatabase.end(); iter1++)
+ {
+ tNFA_HANDLE aidHandle = *iter1;
+ ALOGD ("%s: deregister h=0x%X", fn, aidHandle);
+ SyncEventGuard guard (mDeregisterEvent);
+ nfaStat = NFA_CeDeregisterAidOnDH (aidHandle);
+ if (nfaStat == NFA_STATUS_OK)
+ mDeregisterEvent.wait (); //wait for NFA_CE_DEREGISTERED_EVT
+ else
+ ALOGE ("%s: fail deregister", fn);
+ }
+ mHandleDatabase.clear ();
+ retval = true;
+
+TheEnd:
+ ALOGD ("%s: exit; ok=%u", fn, retval);
+ return retval;
+}
+
+
+/*******************************************************************************
+**
+** Function: startRoute
+**
+** Description: Begin to route AID request to the host.
+** aid: Buffer that contains Application ID
+** aidLen: Actual length of the buffer.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool HostAidRouter::startRoute (const UINT8* aid, UINT8 aidLen)
+{
+ static const char fn [] = "HostAidRouter::startRoute";
+ ALOGD ("%s: enter", fn);
+ tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
+ bool retval = false;
+
+ if (! mIsFeatureEnabled)
+ {
+ ALOGD ("%s: feature disabled", fn);
+ goto TheEnd;
+ }
+
+ {
+ ALOGD ("%s: register AID; len=%u", fn, aidLen);
+ SyncEventGuard guard (mRegisterEvent);
+ mTempHandle = NFA_HANDLE_INVALID;
+ nfaStat = NFA_CeRegisterAidOnDH ((UINT8*) aid, aidLen, stackCallback);
+ if (nfaStat == NFA_STATUS_OK)
+ {
+ mRegisterEvent.wait (); //wait for NFA_CE_REGISTERED_EVT
+ if (mTempHandle == NFA_HANDLE_INVALID)
+ {
+ ALOGE ("%s: received invalid handle", fn);
+ goto TheEnd;
+ }
+ else
+ mHandleDatabase.push_back (mTempHandle);
+ }
+ else
+ {
+ ALOGE ("%s: fail register", fn);
+ goto TheEnd;
+ }
+ }
+
+TheEnd:
+ ALOGD ("%s: exit; ok=%u", fn, retval);
+ return retval;
+}
+
+
+/*******************************************************************************
+**
+** Function: stackCallback
+**
+** Description: Receive events from the NFC stack.
+**
+** Returns: None.
+**
+*******************************************************************************/
+void HostAidRouter::stackCallback (UINT8 event, tNFA_CONN_EVT_DATA* eventData)
+{
+ static const char fn [] = "HostAidRouter::stackCallback";
+ ALOGD("%s: event=0x%X", fn, event);
+
+ switch (event)
+ {
+ case NFA_CE_REGISTERED_EVT:
+ {
+ tNFA_CE_REGISTERED& ce_registered = eventData->ce_registered;
+ ALOGD("%s: NFA_CE_REGISTERED_EVT; status=0x%X; h=0x%X", fn, ce_registered.status, ce_registered.handle);
+ SyncEventGuard guard (sHostAidRouter.mRegisterEvent);
+ if (ce_registered.status == NFA_STATUS_OK)
+ sHostAidRouter.mTempHandle = ce_registered.handle;
+ else
+ sHostAidRouter.mTempHandle = NFA_HANDLE_INVALID;
+ sHostAidRouter.mRegisterEvent.notifyOne();
+ }
+ break;
+
+ case NFA_CE_DEREGISTERED_EVT:
+ {
+ tNFA_CE_DEREGISTERED& ce_deregistered = eventData->ce_deregistered;
+ ALOGD("%s: NFA_CE_DEREGISTERED_EVT; h=0x%X", fn, ce_deregistered.handle);
+ SyncEventGuard guard (sHostAidRouter.mDeregisterEvent);
+ sHostAidRouter.mDeregisterEvent.notifyOne();
+ }
+ break;
+
+ case NFA_CE_DATA_EVT:
+ {
+ tNFA_CE_DATA& ce_data = eventData->ce_data;
+ ALOGD("%s: NFA_CE_DATA_EVT; h=0x%X; data len=%u", fn, ce_data.handle, ce_data.len);
+ SecureElement::getInstance().notifyTransactionListenersOfAid ((UINT8 *)"2PAY.SYS.DDF01", 14);
+ }
+ break;
+ }
+}
diff --git a/nci/jni/HostAidRouter.h b/nci/jni/HostAidRouter.h
new file mode 100644
index 0000000..f653aa9
--- /dev/null
+++ b/nci/jni/HostAidRouter.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+/*
+ * Manage listen-mode AID routing to the host.
+ */
+#pragma once
+#include "SyncEvent.h"
+#include "NfcJniUtil.h"
+#include "RouteDataSet.h"
+#include <vector>
+extern "C"
+{
+ #include "nfa_api.h"
+}
+
+
+class HostAidRouter
+{
+public:
+ /*******************************************************************************
+ **
+ ** Function: getInstance
+ **
+ ** Description: Obtain a reference to the singleton object of HostAidRouter
+ **
+ ** Returns: Reference to HostAidRouter object.
+ **
+ *******************************************************************************/
+ static HostAidRouter& getInstance ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: initialize
+ **
+ ** Description: Initialize all resources.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool initialize ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: addPpseRoute
+ **
+ ** Description: Route Proximity Payment System Environment request
+ ** to the host. This function is called when there is no
+ ** route data.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool addPpseRoute ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: deleteAllRoutes
+ **
+ ** Description: Delete all AID routes to the host.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool deleteAllRoutes ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: isFeatureEnabled
+ **
+ ** Description: Is AID-routing-to-host feature enabled?
+ **
+ ** Returns: True if enabled.
+ **
+ *******************************************************************************/
+ bool isFeatureEnabled () {return mIsFeatureEnabled;};
+
+
+ /*******************************************************************************
+ **
+ ** Function: startRoute
+ **
+ ** Description: Begin to route AID request to the host.
+ ** aid: Buffer that contains Application ID
+ ** aidLen: Actual length of the buffer.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool startRoute (const UINT8* aid, UINT8 aidLen);
+
+
+private:
+ typedef std::vector<tNFA_HANDLE> AidHandleDatabase;
+
+ tNFA_HANDLE mTempHandle;
+ bool mIsFeatureEnabled;
+ static HostAidRouter sHostAidRouter; //singleton object
+ RouteDataSet mRouteDataSet; //route data from xml file
+ SyncEvent mRegisterEvent;
+ SyncEvent mDeregisterEvent;
+ AidHandleDatabase mHandleDatabase; //store all AID handles that are registered with the stack
+
+
+ /*******************************************************************************
+ **
+ ** Function: HostAidRouter
+ **
+ ** Description: Private constructor to prevent public call.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ HostAidRouter ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: ~HostAidRouter
+ **
+ ** Description: Private destructor to prevent public call.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ ~HostAidRouter ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: stackCallback
+ **
+ ** Description: Receive events from the NFC stack.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ static void stackCallback (UINT8 event, tNFA_CONN_EVT_DATA* eventdata);
+};
diff --git a/nci/jni/IntervalTimer.cpp b/nci/jni/IntervalTimer.cpp
new file mode 100644
index 0000000..f71ca8e
--- /dev/null
+++ b/nci/jni/IntervalTimer.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+/*
+ * Asynchronous interval timer.
+ */
+
+#include "IntervalTimer.h"
+#include "OverrideLog.h"
+
+
+IntervalTimer::IntervalTimer()
+{
+ mTimerId = NULL;
+ mCb = NULL;
+}
+
+
+bool IntervalTimer::set(int ms, TIMER_FUNC cb)
+{
+ if (mTimerId == NULL)
+ {
+ if (cb == NULL)
+ return false;
+
+ if (!create(cb))
+ return false;
+ }
+ if (cb != mCb)
+ {
+ kill();
+ if (!create(cb))
+ return false;
+ }
+
+ int stat = 0;
+ struct itimerspec ts;
+ ts.it_value.tv_sec = ms / 1000;
+ ts.it_value.tv_nsec = (ms % 1000) * 1000000;
+
+ ts.it_interval.tv_sec = 0;
+ ts.it_interval.tv_nsec = 0;
+
+ stat = timer_settime(mTimerId, 0, &ts, 0);
+ if (stat == -1)
+ ALOGE("IntervalTimer::set: fail set timer");
+ return stat == 0;
+}
+
+
+IntervalTimer::~IntervalTimer()
+{
+ kill();
+}
+
+
+void IntervalTimer::kill()
+{
+ if (mTimerId == NULL)
+ return;
+
+ timer_delete(mTimerId);
+ mTimerId = NULL;
+ mCb = NULL;
+}
+
+
+bool IntervalTimer::create(TIMER_FUNC cb)
+{
+ struct sigevent se;
+ int stat = 0;
+
+ /*
+ * Set the sigevent structure to cause the signal to be
+ * delivered by creating a new thread.
+ */
+ se.sigev_notify = SIGEV_THREAD;
+ se.sigev_value.sival_ptr = &mTimerId;
+ se.sigev_notify_function = cb;
+ se.sigev_notify_attributes = NULL;
+ mCb = cb;
+ stat = timer_create(CLOCK_MONOTONIC, &se, &mTimerId);
+ if (stat == -1)
+ ALOGE("IntervalTimer::create: fail create timer");
+ return stat == 0;
+}
diff --git a/nci/jni/IntervalTimer.h b/nci/jni/IntervalTimer.h
new file mode 100644
index 0000000..66e345d
--- /dev/null
+++ b/nci/jni/IntervalTimer.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+/*
+ * Asynchronous interval timer.
+ */
+
+#include <time.h>
+
+
+class IntervalTimer
+{
+public:
+ typedef void (*TIMER_FUNC) (union sigval);
+
+ IntervalTimer();
+ ~IntervalTimer();
+ bool set(int ms, TIMER_FUNC cb);
+ void kill();
+ bool create(TIMER_FUNC );
+
+private:
+ timer_t mTimerId;
+ TIMER_FUNC mCb;
+};
diff --git a/nci/jni/JavaClassConstants.h b/nci/jni/JavaClassConstants.h
new file mode 100644
index 0000000..30deca9
--- /dev/null
+++ b/nci/jni/JavaClassConstants.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+#pragma once
+
+
+namespace android
+{
+ extern jmethodID gCachedNfcManagerNotifyNdefMessageListeners;
+ extern jmethodID gCachedNfcManagerNotifyTransactionListeners;
+ extern jmethodID gCachedNfcManagerNotifyLlcpLinkActivation;
+ extern jmethodID gCachedNfcManagerNotifyLlcpLinkDeactivated;
+ extern jmethodID gCachedNfcManagerNotifySeFieldActivated;
+ extern jmethodID gCachedNfcManagerNotifySeFieldDeactivated;
+ extern jmethodID gCachedNfcManagerNotifySeListenActivated;
+ extern jmethodID gCachedNfcManagerNotifySeListenDeactivated;
+
+ extern const char* gNativeP2pDeviceClassName;
+ extern const char* gNativeLlcpServiceSocketClassName;
+ extern const char* gNativeLlcpConnectionlessSocketClassName;
+ extern const char* gNativeLlcpSocketClassName;
+ extern const char* gNativeNfcTagClassName;
+ extern const char* gNativeNfcManagerClassName;
+ extern const char* gNativeNfcSecureElementClassName;
+}
diff --git a/nci/jni/Mutex.cpp b/nci/jni/Mutex.cpp
new file mode 100644
index 0000000..c0b12c0
--- /dev/null
+++ b/nci/jni/Mutex.cpp
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+/*
+ * Encapsulate a mutex for thread synchronization.
+ */
+
+#include "Mutex.h"
+#include "NfcJniUtil.h"
+#include <errno.h>
+
+/*******************************************************************************
+**
+** Function: Mutex
+**
+** Description: Initialize member variables.
+**
+** Returns: None.
+**
+*******************************************************************************/
+Mutex::Mutex ()
+{
+ memset (&mMutex, 0, sizeof(mMutex));
+ int res = pthread_mutex_init (&mMutex, NULL);
+ if (res != 0)
+ {
+ ALOGE ("Mutex::Mutex: fail init; error=0x%X", res);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: ~Mutex
+**
+** Description: Cleanup all resources.
+**
+** Returns: None.
+**
+*******************************************************************************/
+Mutex::~Mutex ()
+{
+ int res = pthread_mutex_destroy (&mMutex);
+ if (res != 0)
+ {
+ ALOGE ("Mutex::~Mutex: fail destroy; error=0x%X", res);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: lock
+**
+** Description: Block the thread and try lock the mutex.
+**
+** Returns: None.
+**
+*******************************************************************************/
+void Mutex::lock ()
+{
+ int res = pthread_mutex_lock (&mMutex);
+ if (res != 0)
+ {
+ ALOGE ("Mutex::lock: fail lock; error=0x%X", res);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: unlock
+**
+** Description: Unlock a mutex to unblock a thread.
+**
+** Returns: None.
+**
+*******************************************************************************/
+void Mutex::unlock ()
+{
+ int res = pthread_mutex_unlock (&mMutex);
+ if (res != 0)
+ {
+ ALOGE ("Mutex::unlock: fail unlock; error=0x%X", res);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: tryLock
+**
+** Description: Try to lock the mutex.
+**
+** Returns: True if the mutex is locked.
+**
+*******************************************************************************/
+bool Mutex::tryLock ()
+{
+ int res = pthread_mutex_trylock (&mMutex);
+ if ((res != 0) && (res != EBUSY))
+ {
+ ALOGE ("Mutex::tryLock: error=0x%X", res);
+ }
+ return res == 0;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeHandle
+**
+** Description: Get the handle of the mutex.
+**
+** Returns: Handle of the mutex.
+**
+*******************************************************************************/
+pthread_mutex_t* Mutex::nativeHandle ()
+{
+ return &mMutex;
+}
+
+
diff --git a/nci/jni/Mutex.h b/nci/jni/Mutex.h
new file mode 100644
index 0000000..45f42de
--- /dev/null
+++ b/nci/jni/Mutex.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+/*
+ * Encapsulate a mutex for thread synchronization.
+ */
+
+#pragma once
+#include <pthread.h>
+
+
+class Mutex
+{
+public:
+ /*******************************************************************************
+ **
+ ** Function: Mutex
+ **
+ ** Description: Initialize member variables.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ Mutex ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: ~Mutex
+ **
+ ** Description: Cleanup all resources.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ ~Mutex ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: lock
+ **
+ ** Description: Block the thread and try lock the mutex.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ void lock ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: unlock
+ **
+ ** Description: Unlock a mutex to unblock a thread.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ void unlock ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: tryLock
+ **
+ ** Description: Try to lock the mutex.
+ **
+ ** Returns: True if the mutex is locked.
+ **
+ *******************************************************************************/
+ bool tryLock ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: nativeHandle
+ **
+ ** Description: Get the handle of the mutex.
+ **
+ ** Returns: Handle of the mutex.
+ **
+ *******************************************************************************/
+ pthread_mutex_t* nativeHandle ();
+
+ class Autolock {
+ public:
+ inline Autolock(Mutex& mutex) : mLock(mutex) { mLock.lock(); }
+ inline Autolock(Mutex* mutex) : mLock(*mutex) { mLock.lock(); }
+ inline ~Autolock() { mLock.unlock(); }
+ private:
+ Mutex& mLock;
+ };
+
+
+private:
+ pthread_mutex_t mMutex;
+};
+
+typedef Mutex::Autolock AutoMutex;
diff --git a/nci/jni/NativeLlcpConnectionlessSocket.cpp b/nci/jni/NativeLlcpConnectionlessSocket.cpp
new file mode 100644
index 0000000..ecc57e3
--- /dev/null
+++ b/nci/jni/NativeLlcpConnectionlessSocket.cpp
@@ -0,0 +1,311 @@
+/*
+ * Copyright (C) 2012 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 <errno.h>
+#include "OverrideLog.h"
+#include "NfcJniUtil.h"
+#include "JavaClassConstants.h"
+extern "C"
+{
+ #include "nfa_api.h"
+ #include "nfa_p2p_api.h"
+}
+
+
+namespace android
+{
+
+
+/*****************************************************************************
+**
+** private variables and functions
+**
+*****************************************************************************/
+static sem_t sConnlessRecvSem;
+static jboolean sConnlessRecvWaitingForData = JNI_FALSE;
+static uint8_t* sConnlessRecvBuf = NULL;
+static uint32_t sConnlessRecvLen = 0;
+static uint32_t sConnlessRecvRemoteSap = 0;
+
+
+/*******************************************************************************
+**
+** Function: nativeLlcpConnectionlessSocket_doSendTo
+**
+** Description: Send data to peer.
+** e: JVM environment.
+** o: Java object.
+** nsap: service access point.
+** data: buffer for data.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+static jboolean nativeLlcpConnectionlessSocket_doSendTo (JNIEnv *e, jobject o, jint nsap, jbyteArray data)
+{
+ tNFA_STATUS status = NFA_STATUS_FAILED;
+ jint handle = 0;
+ uint8_t* buf = NULL;
+ uint32_t len = 0;
+ jclass c = NULL;
+ jfieldID f = NULL;
+
+ ALOGD ("%s: nsap = %d", __FUNCTION__, nsap);
+
+ c = e->GetObjectClass (o);
+ f = e->GetFieldID (c, "mHandle", "I");
+ handle = e->GetIntField (o, f);
+
+ buf = (uint8_t*) e->GetByteArrayElements (data, NULL);
+ len = (uint32_t) e->GetArrayLength (data);
+
+ ALOGD ("NFA_P2pSendUI: len = %d", len);
+ status = NFA_P2pSendUI ((tNFA_HANDLE) handle, nsap, len, buf);
+
+ ALOGD ("%s: NFA_P2pSendUI done, status = %d", __FUNCTION__, status);
+ if (status != NFA_STATUS_OK)
+ {
+ ALOGE ("%s: NFA_P2pSendUI failed, status = %d", __FUNCTION__, status);
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeLlcpConnectionlessSocket_receiveData
+**
+** Description: Receive data from the stack.
+** data: buffer contains data.
+** len: length of data.
+** remoteSap: remote service access point.
+**
+** Returns: None
+**
+*******************************************************************************/
+void nativeLlcpConnectionlessSocket_receiveData (uint8_t* data, uint32_t len, uint32_t remoteSap)
+{
+ ALOGD ("%s: waiting for data = %d, len = %d", __FUNCTION__, sConnlessRecvWaitingForData, len);
+
+ // Sanity...
+ if (sConnlessRecvLen < len)
+ {
+ len = sConnlessRecvLen;
+ }
+
+ if (sConnlessRecvWaitingForData)
+ {
+ sConnlessRecvWaitingForData = JNI_FALSE;
+ sConnlessRecvLen = len;
+ memcpy (sConnlessRecvBuf, data, len);
+ sConnlessRecvRemoteSap = remoteSap;
+
+ sem_post (&sConnlessRecvSem);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: connectionlessCleanup
+**
+** Description: Free resources.
+**
+** Returns: None
+**
+*******************************************************************************/
+static jobject connectionlessCleanup ()
+{
+ sConnlessRecvWaitingForData = JNI_FALSE;
+ sConnlessRecvLen = 0;
+ if (sConnlessRecvBuf != NULL)
+ {
+ free (sConnlessRecvBuf);
+ sConnlessRecvBuf = NULL;
+ }
+ return NULL;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeLlcpConnectionlessSocket_abortWait
+**
+** Description: Abort current operation and unblock threads.
+**
+** Returns: None
+**
+*******************************************************************************/
+void nativeLlcpConnectionlessSocket_abortWait ()
+{
+ sem_post (&sConnlessRecvSem);
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeLlcpConnectionlessSocket_doReceiveFrom
+**
+** Description: Receive data from a peer.
+** e: JVM environment.
+** o: Java object.
+** linkMiu: max info unit
+**
+** Returns: LlcpPacket Java object.
+**
+*******************************************************************************/
+static jobject nativeLlcpConnectionlessSocket_doReceiveFrom (JNIEnv *e, jobject o, jint linkMiu)
+{
+ jbyteArray receivedData = NULL;
+ jobject llcpPacket = NULL;
+ jclass clsLlcpPacket = NULL;
+ jfieldID f = NULL;
+
+ ALOGD ("%s: linkMiu = %d", __FUNCTION__, linkMiu);
+
+ if (sConnlessRecvWaitingForData != JNI_FALSE)
+ {
+ ALOGD ("%s: Already waiting for incoming data", __FUNCTION__);
+ return NULL;
+ }
+
+ sConnlessRecvBuf = (uint8_t*) malloc (linkMiu);
+ if (sConnlessRecvBuf == NULL)
+ {
+ ALOGD ("%s: Failed to allocate %d bytes memory buffer", __FUNCTION__, linkMiu);
+ return NULL;
+ }
+ sConnlessRecvLen = linkMiu;
+
+ // Create the write semaphore
+ if (sem_init (&sConnlessRecvSem, 0, 0) == -1)
+ {
+ ALOGE ("%s: semaphore creation failed (errno=0x%08x)", __FUNCTION__, errno);
+ return connectionlessCleanup ();
+ }
+
+ sConnlessRecvWaitingForData = JNI_TRUE;
+
+ // Wait for sConnlessRecvSem completion status
+ if (sem_wait (&sConnlessRecvSem))
+ {
+ ALOGE ("%s: Failed to wait for write semaphore (errno=0x%08x)", __FUNCTION__, errno);
+ goto TheEnd;
+ }
+
+ // Create new LlcpPacket object
+ if (nfc_jni_cache_object (e, "com/android/nfc/LlcpPacket", &(llcpPacket)) == -1)
+ {
+ ALOGE ("%s: Find LlcpPacket class error", __FUNCTION__);
+ return connectionlessCleanup ();
+ }
+
+ // Get NativeConnectionless class object
+ clsLlcpPacket = e->GetObjectClass (llcpPacket);
+ if (e->ExceptionCheck ())
+ {
+ e->ExceptionClear();
+ ALOGE ("%s: Get Object class error", __FUNCTION__);
+ return connectionlessCleanup ();
+ }
+
+ // Set Llcp Packet remote SAP
+ f = e->GetFieldID (clsLlcpPacket, "mRemoteSap", "I");
+ e->SetIntField (llcpPacket, f, (jbyte) sConnlessRecvRemoteSap);
+
+ // Set Llcp Packet Buffer
+ ALOGD ("%s: Received Llcp packet buffer size = %d\n", __FUNCTION__, sConnlessRecvLen);
+ f = e->GetFieldID (clsLlcpPacket, "mDataBuffer", "[B");
+ receivedData = e->NewByteArray (sConnlessRecvLen);
+ e->SetByteArrayRegion (receivedData, 0, sConnlessRecvLen, (jbyte*) sConnlessRecvBuf);
+ e->SetObjectField (llcpPacket, f, receivedData);
+
+TheEnd:
+ connectionlessCleanup ();
+ if (sem_destroy (&sConnlessRecvSem))
+ {
+ ALOGE ("%s: Failed to destroy sConnlessRecvSem semaphore (errno=0x%08x)", __FUNCTION__, errno);
+ }
+ return llcpPacket;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeLlcpConnectionlessSocket_doClose
+**
+** Description: Close socket.
+** e: JVM environment.
+** o: Java object.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+static jboolean nativeLlcpConnectionlessSocket_doClose (JNIEnv *e, jobject o)
+{
+ tNFA_STATUS status = NFA_STATUS_FAILED;
+ jint handle = 0;
+ jclass c = NULL;
+ jfieldID f = NULL;
+
+ ALOGD ("%s", __FUNCTION__);
+
+ c = e->GetObjectClass (o);
+ f = e->GetFieldID (c, "mHandle", "I");
+ handle = e->GetIntField (o, f);
+
+ status = NFA_P2pDisconnect ((tNFA_HANDLE) handle, FALSE);
+ if (status != NFA_STATUS_OK)
+ {
+ ALOGE ("%s: disconnect failed, status = %d", __FUNCTION__, status);
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
+}
+
+
+/*****************************************************************************
+**
+** Description: JNI functions
+**
+*****************************************************************************/
+static JNINativeMethod gMethods[] =
+{
+ {"doSendTo", "(I[B)Z", (void*) nativeLlcpConnectionlessSocket_doSendTo},
+ {"doReceiveFrom", "(I)Lcom/android/nfc/LlcpPacket;", (void*) nativeLlcpConnectionlessSocket_doReceiveFrom},
+ {"doClose", "()Z", (void*) nativeLlcpConnectionlessSocket_doClose},
+};
+
+
+/*******************************************************************************
+**
+** Function: register_com_android_nfc_NativeLlcpConnectionlessSocket
+**
+** Description: Regisgter JNI functions with Java Virtual Machine.
+** e: Environment of JVM.
+**
+** Returns: Status of registration.
+**
+*******************************************************************************/
+int register_com_android_nfc_NativeLlcpConnectionlessSocket (JNIEnv *e)
+{
+ return jniRegisterNativeMethods (e, gNativeLlcpConnectionlessSocketClassName, gMethods, NELEM(gMethods));
+}
+
+
+} // android namespace
diff --git a/nci/jni/NativeLlcpServiceSocket.cpp b/nci/jni/NativeLlcpServiceSocket.cpp
new file mode 100644
index 0000000..e1c2bb5
--- /dev/null
+++ b/nci/jni/NativeLlcpServiceSocket.cpp
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2012 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 "OverrideLog.h"
+#include "NfcJniUtil.h"
+#include "NfcAdaptation.h"
+#include "PeerToPeer.h"
+#include "JavaClassConstants.h"
+extern "C"
+{
+ #include "nfa_api.h"
+ #include "nfa_p2p_api.h"
+}
+
+
+namespace android
+{
+
+
+/*******************************************************************************
+**
+** Function: nativeLlcpServiceSocket_doAccept
+**
+** Description: Accept a connection request from a peer.
+** e: JVM environment.
+** o: Java object.
+** miu: Maximum information unit.
+** rw: Receive window.
+** linearBufferLength: Not used.
+**
+** Returns: LlcpSocket Java object.
+**
+*******************************************************************************/
+static jobject nativeLlcpServiceSocket_doAccept(JNIEnv *e, jobject o, jint miu, jint rw, jint linearBufferLength)
+{
+ jobject clientSocket = NULL;
+ jclass clsNativeLlcpSocket = NULL;
+ jfieldID f = 0;
+ PeerToPeer::tJNI_HANDLE serverHandle; //handle of the local server
+ bool stat = false;
+ PeerToPeer::tJNI_HANDLE connHandle = PeerToPeer::getInstance().getNewJniHandle ();
+
+ ALOGD ("%s: enter", __FUNCTION__);
+
+ serverHandle = (PeerToPeer::tJNI_HANDLE) nfc_jni_get_nfc_socket_handle (e, o);
+
+ stat = PeerToPeer::getInstance().accept (serverHandle, connHandle, miu, rw);
+
+ if (! stat)
+ {
+ ALOGE ("%s: fail accept", __FUNCTION__);
+ goto TheEnd;
+ }
+
+ /* Create new LlcpSocket object */
+ if (nfc_jni_cache_object(e, gNativeLlcpSocketClassName, &(clientSocket)) == -1)
+ {
+ ALOGE ("%s: fail create NativeLlcpSocket", __FUNCTION__);
+ goto TheEnd;
+ }
+
+ /* Get NativeConnectionOriented class object */
+ clsNativeLlcpSocket = e->GetObjectClass (clientSocket);
+ if (e->ExceptionCheck())
+ {
+ e->ExceptionClear();
+ ALOGE ("%s: get class object error", __FUNCTION__);
+ goto TheEnd;
+ }
+
+ /* Set socket handle */
+ f = e->GetFieldID (clsNativeLlcpSocket, "mHandle", "I");
+ e->SetIntField (clientSocket, f, (jint) connHandle);
+
+ /* Set socket MIU */
+ f = e->GetFieldID (clsNativeLlcpSocket, "mLocalMiu", "I");
+ e->SetIntField (clientSocket, f, (jint)miu);
+
+ /* Set socket RW */
+ f = e->GetFieldID (clsNativeLlcpSocket, "mLocalRw", "I");
+ e->SetIntField (clientSocket, f, (jint)rw);
+
+TheEnd:
+ ALOGD ("%s: exit", __FUNCTION__);
+ return clientSocket;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeLlcpServiceSocket_doClose
+**
+** Description: Close a server socket.
+** e: JVM environment.
+** o: Java object.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+static jboolean nativeLlcpServiceSocket_doClose(JNIEnv *e, jobject o)
+{
+ ALOGD ("%s: enter", __FUNCTION__);
+ PeerToPeer::tJNI_HANDLE jniServerHandle = 0;
+ bool stat = false;
+
+ jniServerHandle = nfc_jni_get_nfc_socket_handle (e, o);
+
+ stat = PeerToPeer::getInstance().deregisterServer (jniServerHandle);
+
+ ALOGD ("%s: exit", __FUNCTION__);
+ return JNI_TRUE;
+}
+
+
+/*****************************************************************************
+**
+** Description: JNI functions
+**
+*****************************************************************************/
+static JNINativeMethod gMethods[] =
+{
+ {"doAccept", "(III)Lcom/android/nfc/dhimpl/NativeLlcpSocket;", (void*) nativeLlcpServiceSocket_doAccept},
+ {"doClose", "()Z", (void*) nativeLlcpServiceSocket_doClose},
+};
+
+
+/*******************************************************************************
+**
+** Function: register_com_android_nfc_NativeLlcpServiceSocket
+**
+** Description: Regisgter JNI functions with Java Virtual Machine.
+** e: Environment of JVM.
+**
+** Returns: Status of registration.
+**
+*******************************************************************************/
+int register_com_android_nfc_NativeLlcpServiceSocket (JNIEnv* e)
+{
+ return jniRegisterNativeMethods (e, gNativeLlcpServiceSocketClassName,
+ gMethods, NELEM(gMethods));
+}
+
+
+} //namespace android
+
diff --git a/nci/jni/NativeLlcpSocket.cpp b/nci/jni/NativeLlcpSocket.cpp
new file mode 100644
index 0000000..74a59b9
--- /dev/null
+++ b/nci/jni/NativeLlcpSocket.cpp
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2012 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 "OverrideLog.h"
+#include "PeerToPeer.h"
+#include "JavaClassConstants.h"
+
+
+namespace android
+{
+
+
+/*******************************************************************************
+**
+** Function: nativeLlcpSocket_doConnect
+**
+** Description: Establish a connection to the peer.
+** e: JVM environment.
+** o: Java object.
+** nSap: Service access point.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+static jboolean nativeLlcpSocket_doConnect (JNIEnv* e, jobject o, jint nSap)
+{
+ bool stat = false;
+ jboolean retVal = JNI_FALSE;
+
+ ALOGD ("%s: enter; sap=%d", __FUNCTION__, nSap);
+
+ PeerToPeer::tJNI_HANDLE jniHandle = (PeerToPeer::tJNI_HANDLE) nfc_jni_get_nfc_socket_handle (e,o);
+
+ stat = PeerToPeer::getInstance().connectConnOriented (jniHandle, nSap);
+
+ if (stat)
+ retVal = JNI_TRUE;
+
+ ALOGD ("%s: exit", __FUNCTION__);
+ return retVal;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeLlcpSocket_doConnectBy
+**
+** Description: Establish a connection to the peer.
+** e: JVM environment.
+** o: Java object.
+** sn: Service name.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+static jboolean nativeLlcpSocket_doConnectBy (JNIEnv* e, jobject o, jstring sn)
+{
+ ALOGD ("%s: enter", __FUNCTION__);
+ bool stat = false;
+ jboolean retVal = JNI_FALSE;
+
+ PeerToPeer::tJNI_HANDLE jniHandle = (PeerToPeer::tJNI_HANDLE) nfc_jni_get_nfc_socket_handle (e,o);
+
+ const char* serviceName = e->GetStringUTFChars (sn, JNI_FALSE); //convert jstring, which is unicode, into char*
+
+ stat = PeerToPeer::getInstance().connectConnOriented (jniHandle, serviceName);
+
+ e->ReleaseStringUTFChars (sn, serviceName); //free the string
+
+ if (stat)
+ retVal = JNI_TRUE;
+
+ ALOGD ("%s: exit", __FUNCTION__);
+ return retVal;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeLlcpSocket_doClose
+**
+** Description: Close socket.
+** e: JVM environment.
+** o: Java object.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+static jboolean nativeLlcpSocket_doClose(JNIEnv *e, jobject o)
+{
+ ALOGD ("%s: enter", __FUNCTION__);
+ bool stat = false;
+ jboolean retVal = JNI_FALSE;
+
+ PeerToPeer::tJNI_HANDLE jniHandle = (PeerToPeer::tJNI_HANDLE) nfc_jni_get_nfc_socket_handle (e,o);
+
+ stat = PeerToPeer::getInstance().disconnectConnOriented (jniHandle);
+
+ retVal = JNI_TRUE;
+ ALOGD ("%s: exit", __FUNCTION__);
+ return retVal;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeLlcpSocket_doSend
+**
+** Description: Send data to peer.
+** e: JVM environment.
+** o: Java object.
+** data: Buffer of data.
+**
+** Returns: True if sent ok.
+**
+*******************************************************************************/
+static jboolean nativeLlcpSocket_doSend (JNIEnv* e, jobject o, jbyteArray data)
+{
+ ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: enter", __FUNCTION__);
+ uint8_t* dataBuffer = (uint8_t*) e->GetByteArrayElements (data, NULL);
+ uint32_t dataBufferLen = (uint32_t) e->GetArrayLength (data);
+ bool stat = false;
+
+ PeerToPeer::tJNI_HANDLE jniHandle = (PeerToPeer::tJNI_HANDLE) nfc_jni_get_nfc_socket_handle (e,o);
+
+ stat = PeerToPeer::getInstance().send (jniHandle, dataBuffer, dataBufferLen);
+
+ e->ReleaseByteArrayElements (data, (jbyte*) dataBuffer, JNI_ABORT);
+
+ ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: exit", __FUNCTION__);
+ return stat ? JNI_TRUE : JNI_FALSE;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeLlcpSocket_doReceive
+**
+** Description: Receive data from peer.
+** e: JVM environment.
+** o: Java object.
+** origBuffer: Buffer to put received data.
+**
+** Returns: Number of bytes received.
+**
+*******************************************************************************/
+static jint nativeLlcpSocket_doReceive(JNIEnv *e, jobject o, jbyteArray origBuffer)
+{
+ ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: enter", __FUNCTION__);
+ uint8_t* dataBuffer = (uint8_t*) e->GetByteArrayElements (origBuffer, NULL);
+ uint32_t dataBufferLen = (uint32_t) e->GetArrayLength (origBuffer);
+ uint16_t actualLen = 0;
+ bool stat = false;
+ jint retval = 0;
+
+ PeerToPeer::tJNI_HANDLE jniHandle = (PeerToPeer::tJNI_HANDLE) nfc_jni_get_nfc_socket_handle (e,o);
+
+ stat = PeerToPeer::getInstance().receive (jniHandle, dataBuffer, dataBufferLen, actualLen);
+
+ if (stat && (actualLen>0))
+ {
+ retval = actualLen;
+ }
+ else
+ retval = -1;
+
+ e->ReleaseByteArrayElements (origBuffer, (jbyte*) dataBuffer, 0);
+ ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: exit; actual len=%d", __FUNCTION__, retval);
+ return retval;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeLlcpSocket_doGetRemoteSocketMIU
+**
+** Description: Get peer's maximum information unit.
+** e: JVM environment.
+** o: Java object.
+**
+** Returns: Peer's maximum information unit.
+**
+*******************************************************************************/
+static jint nativeLlcpSocket_doGetRemoteSocketMIU (JNIEnv* e, jobject o)
+{
+ ALOGD ("%s: enter", __FUNCTION__);
+ bool stat = false;
+
+ PeerToPeer::tJNI_HANDLE jniHandle = (PeerToPeer::tJNI_HANDLE) nfc_jni_get_nfc_socket_handle (e,o);
+ jint miu = 0;
+
+ miu = PeerToPeer::getInstance().getRemoteMaxInfoUnit (jniHandle);
+
+ ALOGD ("%s: exit", __FUNCTION__);
+ return miu;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeLlcpSocket_doGetRemoteSocketRW
+**
+** Description: Get peer's receive window size.
+** e: JVM environment.
+** o: Java object.
+**
+** Returns: Peer's receive window size.
+**
+*******************************************************************************/
+static jint nativeLlcpSocket_doGetRemoteSocketRW (JNIEnv* e, jobject o)
+{
+ ALOGD ("%s: enter", __FUNCTION__);
+ bool stat = false;
+ jint rw = 0;
+
+ PeerToPeer::tJNI_HANDLE jniHandle = (PeerToPeer::tJNI_HANDLE) nfc_jni_get_nfc_socket_handle (e,o);
+
+ rw = PeerToPeer::getInstance().getRemoteRecvWindow (jniHandle);
+
+ ALOGD ("%s: exit", __FUNCTION__);
+ return rw;
+}
+
+
+/*****************************************************************************
+**
+** Description: JNI functions
+**
+*****************************************************************************/
+static JNINativeMethod gMethods[] =
+{
+ {"doConnect", "(I)Z", (void * ) nativeLlcpSocket_doConnect},
+ {"doConnectBy", "(Ljava/lang/String;)Z", (void*) nativeLlcpSocket_doConnectBy},
+ {"doClose", "()Z", (void *) nativeLlcpSocket_doClose},
+ {"doSend", "([B)Z", (void *) nativeLlcpSocket_doSend},
+ {"doReceive", "([B)I", (void *) nativeLlcpSocket_doReceive},
+ {"doGetRemoteSocketMiu", "()I", (void *) nativeLlcpSocket_doGetRemoteSocketMIU},
+ {"doGetRemoteSocketRw", "()I", (void *) nativeLlcpSocket_doGetRemoteSocketRW},
+};
+
+
+/*******************************************************************************
+**
+** Function: register_com_android_nfc_NativeLlcpSocket
+**
+** Description: Regisgter JNI functions with Java Virtual Machine.
+** e: Environment of JVM.
+**
+** Returns: Status of registration.
+**
+*******************************************************************************/
+int register_com_android_nfc_NativeLlcpSocket (JNIEnv* e)
+{
+ return jniRegisterNativeMethods (e, gNativeLlcpSocketClassName, gMethods, NELEM(gMethods));
+}
+
+
+} //namespace android
+
diff --git a/nci/jni/NativeNfcManager.cpp b/nci/jni/NativeNfcManager.cpp
new file mode 100755
index 0000000..f15c92f
--- /dev/null
+++ b/nci/jni/NativeNfcManager.cpp
@@ -0,0 +1,1816 @@
+/*
+ * Copyright (C) 2012 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 <errno.h>
+#include "OverrideLog.h"
+#include "NfcJniUtil.h"
+#include "NfcAdaptation.h"
+#include "SyncEvent.h"
+#include "PeerToPeer.h"
+#include "SecureElement.h"
+#include "NfcTag.h"
+#include "config.h"
+#include "PowerSwitch.h"
+#include "JavaClassConstants.h"
+#include "Pn544Interop.h"
+
+extern "C"
+{
+ #include "nfa_api.h"
+ #include "nfa_p2p_api.h"
+ #include "rw_api.h"
+ #include "nfa_ee_api.h"
+ #include "nfc_brcm_defs.h"
+ #include "nfa_cho_api.h"
+ #include "ce_api.h"
+}
+
+extern UINT8 *p_nfa_dm_lptd_cfg;
+extern UINT8 *p_nfa_dm_start_up_cfg;
+extern const UINT8 nfca_version_string [];
+namespace android
+{
+ extern bool gIsTagDeactivating;
+ extern bool gIsSelectingRfInterface;
+ extern void nativeNfcTag_doTransceiveStatus (uint8_t * buf, uint32_t buflen);
+ extern void nativeNfcTag_doConnectStatus (jboolean is_connect_ok);
+ extern void nativeNfcTag_doDeactivateStatus (int status);
+ extern void nativeNfcTag_doWriteStatus (jboolean is_write_ok);
+ extern void nativeNfcTag_doCheckNdefResult (tNFA_STATUS status, uint32_t max_size, uint32_t current_size, uint8_t flags);
+ extern void nativeNfcTag_doMakeReadonlyResult (tNFA_STATUS status);
+ extern void nativeNfcTag_doPresenceCheckResult (tNFA_STATUS status);
+ extern void nativeNfcTag_formatStatus (bool is_ok);
+ extern void nativeNfcTag_resetPresenceCheck ();
+ extern void nativeNfcTag_doReadCompleted (tNFA_STATUS status);
+ extern void nativeNfcTag_abortWaits ();
+ extern void nativeLlcpConnectionlessSocket_abortWait ();
+ extern void nativeNfcTag_registerNdefTypeHandler ();
+ extern void nativeLlcpConnectionlessSocket_receiveData (uint8_t* data, uint32_t len, uint32_t remote_sap);
+}
+
+
+/*****************************************************************************
+**
+** public variables and functions
+**
+*****************************************************************************/
+
+namespace android
+{
+ int gGeneralTransceiveTimeout = 1000;
+ jmethodID gCachedNfcManagerNotifyNdefMessageListeners;
+ jmethodID gCachedNfcManagerNotifyTransactionListeners;
+ jmethodID gCachedNfcManagerNotifyLlcpLinkActivation;
+ jmethodID gCachedNfcManagerNotifyLlcpLinkDeactivated;
+ jmethodID gCachedNfcManagerNotifySeFieldActivated;
+ jmethodID gCachedNfcManagerNotifySeFieldDeactivated;
+ jmethodID gCachedNfcManagerNotifySeListenActivated;
+ jmethodID gCachedNfcManagerNotifySeListenDeactivated;
+ const char* gNativeP2pDeviceClassName = "com/android/nfc/dhimpl/NativeP2pDevice";
+ const char* gNativeLlcpServiceSocketClassName = "com/android/nfc/dhimpl/NativeLlcpServiceSocket";
+ const char* gNativeLlcpConnectionlessSocketClassName = "com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket";
+ const char* gNativeLlcpSocketClassName = "com/android/nfc/dhimpl/NativeLlcpSocket";
+ const char* gNativeNfcTagClassName = "com/android/nfc/dhimpl/NativeNfcTag";
+ const char* gNativeNfcManagerClassName = "com/android/nfc/dhimpl/NativeNfcManager";
+ const char* gNativeNfcSecureElementClassName = "com/android/nfc/dhimpl/NativeNfcSecureElement";
+ void doStartupConfig ();
+ void startStopPolling (bool isStartPolling);
+ void startRfDiscovery (bool isStart);
+}
+
+
+/*****************************************************************************
+**
+** private variables and functions
+**
+*****************************************************************************/
+namespace android
+{
+static jint sLastError = ERROR_BUFFER_TOO_SMALL;
+static jmethodID sCachedNfcManagerNotifySeApduReceived;
+static jmethodID sCachedNfcManagerNotifySeMifareAccess;
+static jmethodID sCachedNfcManagerNotifySeEmvCardRemoval;
+static jmethodID sCachedNfcManagerNotifyTargetDeselected;
+static SyncEvent sNfaEnableEvent; //event for NFA_Enable()
+static SyncEvent sNfaDisableEvent; //event for NFA_Disable()
+static SyncEvent sNfaEnableDisablePollingEvent; //event for NFA_EnablePolling(), NFA_DisablePolling()
+static SyncEvent sNfaSetConfigEvent; // event for Set_Config....
+static bool sIsNfaEnabled = false;
+static bool sDiscoveryEnabled = false; //is polling for tag?
+static bool sIsDisabling = false;
+static bool sRfEnabled = false; // whether RF discovery is enabled
+static bool sSeRfActive = false; // whether RF with SE is likely active
+static bool sP2pActive = false; // whether p2p was last active
+static int sConnlessSap = 0;
+static int sConnlessLinkMiu = 0;
+static bool sAbortConnlessWait = false;
+static bool sIsSecElemSelected = false; //has NFC service selected a sec elem
+static UINT8 * sOriginalLptdCfg = NULL;
+static UINT8 sNewLptdCfg[LPTD_PARAM_LEN];
+static UINT32 sConfigUpdated = 0;
+#define CONFIG_UPDATE_LPTD (1 << 0)
+#define CONFIG_UPDATE_TECH_MASK (1 << 1)
+#define DEFAULT_TECH_MASK (NFA_TECHNOLOGY_MASK_A \
+ | NFA_TECHNOLOGY_MASK_B \
+ | NFA_TECHNOLOGY_MASK_F \
+ | NFA_TECHNOLOGY_MASK_ISO15693 \
+ | NFA_TECHNOLOGY_MASK_B_PRIME \
+ | NFA_TECHNOLOGY_MASK_A_ACTIVE \
+ | NFA_TECHNOLOGY_MASK_F_ACTIVE)
+
+
+static void nfaConnectionCallback (UINT8 event, tNFA_CONN_EVT_DATA *eventData);
+static void nfaDeviceManagementCallback (UINT8 event, tNFA_DM_CBACK_DATA *eventData);
+static bool isPeerToPeer (tNFA_ACTIVATED& activated);
+static bool isListenMode(tNFA_ACTIVATED& activated);
+
+/////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////
+
+
+/*******************************************************************************
+**
+** Function: getNative
+**
+** Description: Get native data
+**
+** Returns: Native data structure.
+**
+*******************************************************************************/
+nfc_jni_native_data *getNative (JNIEnv* e, jobject o)
+{
+ static struct nfc_jni_native_data *sCachedNat = NULL;
+ if (e)
+ {
+ sCachedNat = nfc_jni_get_nat(e, o);
+ }
+ return sCachedNat;
+}
+
+
+/*******************************************************************************
+**
+** Function: handleRfDiscoveryEvent
+**
+** Description: Handle RF-discovery events from the stack.
+** discoveredDevice: Discovered device.
+**
+** Returns: None
+**
+*******************************************************************************/
+static void handleRfDiscoveryEvent (tNFC_RESULT_DEVT* discoveredDevice)
+{
+ if (discoveredDevice->more)
+ {
+ //there is more discovery notification coming
+ return;
+ }
+
+ bool isP2p = NfcTag::getInstance ().isP2pDiscovered ();
+ if (isP2p)
+ {
+ //select the peer that supports P2P
+ NfcTag::getInstance ().selectP2p();
+ }
+ else
+ {
+ //select the first of multiple tags that is discovered
+ NfcTag::getInstance ().selectFirstTag();
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: nfaConnectionCallback
+**
+** Description: Receive connection-related events from stack.
+** connEvent: Event code.
+** eventData: Event data.
+**
+** Returns: None
+**
+*******************************************************************************/
+static void nfaConnectionCallback (UINT8 connEvent, tNFA_CONN_EVT_DATA* eventData)
+{
+ tNFA_STATUS status = NFA_STATUS_FAILED;
+ ALOGD("%s: event= %u", __FUNCTION__, connEvent);
+
+ if (gIsTagDeactivating && connEvent != NFA_DEACTIVATED_EVT && connEvent != NFA_PRESENCE_CHECK_EVT && connEvent != NFA_DATA_EVT)
+ {
+ // special case to switching frame interface for ISO_DEP tags
+ gIsTagDeactivating = false;
+ ALOGD("%s: deactivating, should get NFA_DEACTIVATED_EVT", __FUNCTION__);
+ nativeNfcTag_doDeactivateStatus(1);
+ }
+
+ switch (connEvent)
+ {
+ case NFA_POLL_ENABLED_EVT: // whether polling successfully started
+ {
+ ALOGD("%s: NFA_POLL_ENABLED_EVT: status = %u", __FUNCTION__, eventData->status);
+
+ SyncEventGuard guard (sNfaEnableDisablePollingEvent);
+ sNfaEnableDisablePollingEvent.notifyOne ();
+ }
+ break;
+
+ case NFA_POLL_DISABLED_EVT: // Listening/Polling stopped
+ {
+ ALOGD("%s: NFA_POLL_DISABLED_EVT: status = %u", __FUNCTION__, eventData->status);
+
+ SyncEventGuard guard (sNfaEnableDisablePollingEvent);
+ sNfaEnableDisablePollingEvent.notifyOne ();
+ }
+ break;
+
+ case NFA_RF_DISCOVERY_STARTED_EVT: // RF Discovery started
+ {
+ ALOGD("%s: NFA_RF_DISCOVERY_STARTED_EVT: status = %u", __FUNCTION__, eventData->status);
+
+ SyncEventGuard guard (sNfaEnableDisablePollingEvent);
+ sNfaEnableDisablePollingEvent.notifyOne ();
+ }
+ break;
+
+ case NFA_RF_DISCOVERY_STOPPED_EVT: // RF Discovery stopped event
+ {
+ ALOGD("%s: NFA_RF_DISCOVERY_STOPPED_EVT: status = %u", __FUNCTION__, eventData->status);
+
+ SyncEventGuard guard (sNfaEnableDisablePollingEvent);
+ sNfaEnableDisablePollingEvent.notifyOne ();
+ }
+ break;
+
+ case NFA_DISC_RESULT_EVT: // NFC link/protocol discovery notificaiton
+ status = eventData->disc_result.status;
+ ALOGD("%s: NFA_DISC_RESULT_EVT: status = %d", __FUNCTION__, status);
+ if (status != NFA_STATUS_OK)
+ {
+ ALOGE("%s: NFA_DISC_RESULT_EVT error: status = %d", __FUNCTION__, status);
+ }
+ else
+ {
+ NfcTag::getInstance().connectionEventHandler(connEvent, eventData);
+ handleRfDiscoveryEvent(&eventData->disc_result.discovery_ntf);
+ }
+ break;
+
+ case NFA_SELECT_RESULT_EVT: // NFC link/protocol discovery select response
+ ALOGD("%s: NFA_SELECT_RESULT_EVT: status = %d, gIsSelectingRfInterface = %d, sIsDisabling=%d", __FUNCTION__, eventData->status, gIsSelectingRfInterface, sIsDisabling);
+
+ if (sIsDisabling)
+ break;
+
+ if (eventData->status != NFA_STATUS_OK)
+ {
+ if (gIsSelectingRfInterface)
+ {
+ nativeNfcTag_doConnectStatus(false);
+ }
+
+ ALOGE("%s: NFA_SELECT_RESULT_EVT error: status = %d", __FUNCTION__, eventData->status);
+ NFA_Deactivate (FALSE);
+ }
+ break;
+
+ case NFA_DEACTIVATE_FAIL_EVT:
+ ALOGD("%s: NFA_DEACTIVATE_FAIL_EVT: status = %d", __FUNCTION__, eventData->status);
+ break;
+
+ case NFA_ACTIVATED_EVT: // NFC link/protocol activated
+ ALOGD("%s: NFA_ACTIVATED_EVT: gIsSelectingRfInterface=%d, sIsDisabling=%d", __FUNCTION__, gIsSelectingRfInterface, sIsDisabling);
+ if (sIsDisabling)
+ break;
+
+ NfcTag::getInstance().setActivationState ();
+ if (gIsSelectingRfInterface)
+ {
+ nativeNfcTag_doConnectStatus(true);
+ break;
+ }
+
+ nativeNfcTag_resetPresenceCheck();
+ if (isPeerToPeer(eventData->activated))
+ {
+ sP2pActive = true;
+ ALOGD("%s: NFA_ACTIVATED_EVT; is p2p", __FUNCTION__);
+ // Disable RF field events in case of p2p
+ UINT8 nfa_disable_rf_events[] = { 0x00 };
+ ALOGD ("%s: Disabling RF field events", __FUNCTION__);
+ status = NFA_SetConfig(NCI_PARAM_ID_RF_FIELD_INFO, sizeof(nfa_disable_rf_events),
+ &nfa_disable_rf_events[0]);
+ if (status == NFA_STATUS_OK) {
+ ALOGD ("%s: Disabled RF field events", __FUNCTION__);
+ } else {
+ ALOGE ("%s: Failed to disable RF field events", __FUNCTION__);
+ }
+ }
+ else if (pn544InteropIsBusy() == false)
+ {
+ NfcTag::getInstance().connectionEventHandler (connEvent, eventData);
+
+ // We know it is not activating for P2P. If it activated in
+ // listen mode then it is likely for and SE transaction.
+ // Send the RF Event.
+ if (isListenMode(eventData->activated))
+ {
+ sSeRfActive = true;
+ SecureElement::getInstance().notifyListenModeState (true);
+ }
+ }
+
+ break;
+
+ case NFA_DEACTIVATED_EVT: // NFC link/protocol deactivated
+ ALOGD("%s: NFA_DEACTIVATED_EVT Type: %u, gIsTagDeactivating: %d", __FUNCTION__, eventData->deactivated.type,gIsTagDeactivating);
+ NfcTag::getInstance().setDeactivationState (eventData->deactivated);
+ if (eventData->deactivated.type != NFA_DEACTIVATE_TYPE_SLEEP)
+ {
+ nativeNfcTag_resetPresenceCheck();
+ NfcTag::getInstance().connectionEventHandler (connEvent, eventData);
+ nativeNfcTag_abortWaits();
+ NfcTag::getInstance().abort ();
+ }
+ else if (gIsTagDeactivating)
+ {
+ nativeNfcTag_doDeactivateStatus(0);
+ }
+
+ // If RF is activated for what we think is a Secure Element transaction
+ // and it is deactivated to either IDLE or DISCOVERY mode, notify w/event.
+ if ((eventData->deactivated.type == NFA_DEACTIVATE_TYPE_IDLE)
+ || (eventData->deactivated.type == NFA_DEACTIVATE_TYPE_DISCOVERY))
+ {
+ if (sSeRfActive) {
+ sSeRfActive = false;
+ SecureElement::getInstance().notifyListenModeState (false);
+ } else if (sP2pActive) {
+ sP2pActive = false;
+ // Make sure RF field events are re-enabled
+ ALOGD("%s: NFA_ACTIVATED_EVT; is p2p", __FUNCTION__);
+ // Disable RF field events in case of p2p
+ UINT8 nfa_enable_rf_events[] = { 0x01 };
+
+ ALOGD ("%s: Enabling RF field events", __FUNCTION__);
+ status = NFA_SetConfig(NCI_PARAM_ID_RF_FIELD_INFO, sizeof(nfa_enable_rf_events),
+ &nfa_enable_rf_events[0]);
+ if (status == NFA_STATUS_OK) {
+ ALOGD ("%s: Enabled RF field events", __FUNCTION__);
+ } else {
+ ALOGE ("%s: Failed to enable RF field events", __FUNCTION__);
+ }
+ }
+ }
+
+ break;
+
+ case NFA_TLV_DETECT_EVT: // TLV Detection complete
+ status = eventData->tlv_detect.status;
+ ALOGD("%s: NFA_TLV_DETECT_EVT: status = %d, protocol = %d, num_tlvs = %d, num_bytes = %d",
+ __FUNCTION__, status, eventData->tlv_detect.protocol,
+ eventData->tlv_detect.num_tlvs, eventData->tlv_detect.num_bytes);
+ if (status != NFA_STATUS_OK)
+ {
+ ALOGE("%s: NFA_TLV_DETECT_EVT error: status = %d", __FUNCTION__, status);
+ }
+ break;
+
+ case NFA_NDEF_DETECT_EVT: // NDEF Detection complete;
+ //if status is failure, it means the tag does not contain any or valid NDEF data;
+ //pass the failure status to the NFC Service;
+ status = eventData->ndef_detect.status;
+ ALOGD("%s: NFA_NDEF_DETECT_EVT: status = 0x%X, protocol = %u, "
+ "max_size = %lu, cur_size = %lu, flags = 0x%X", __FUNCTION__,
+ status,
+ eventData->ndef_detect.protocol, eventData->ndef_detect.max_size,
+ eventData->ndef_detect.cur_size, eventData->ndef_detect.flags);
+ NfcTag::getInstance().connectionEventHandler (connEvent, eventData);
+ nativeNfcTag_doCheckNdefResult(status,
+ eventData->ndef_detect.max_size, eventData->ndef_detect.cur_size,
+ eventData->ndef_detect.flags);
+ break;
+
+ case NFA_DATA_EVT: // Data message received (for non-NDEF reads)
+ ALOGD("%s: NFA_DATA_EVT: len = %d", __FUNCTION__, eventData->data.len);
+ nativeNfcTag_doTransceiveStatus(eventData->data.p_data,eventData->data.len);
+ break;
+
+ case NFA_SELECT_CPLT_EVT: // Select completed
+ status = eventData->status;
+ ALOGD("%s: NFA_SELECT_CPLT_EVT: status = %d", __FUNCTION__, status);
+ if (status != NFA_STATUS_OK)
+ {
+ ALOGE("%s: NFA_SELECT_CPLT_EVT error: status = %d", __FUNCTION__, status);
+ }
+ break;
+
+ case NFA_READ_CPLT_EVT: // NDEF-read or tag-specific-read completed
+ ALOGD("%s: NFA_READ_CPLT_EVT: status = 0x%X", __FUNCTION__, eventData->status);
+ nativeNfcTag_doReadCompleted (eventData->status);
+ NfcTag::getInstance().connectionEventHandler (connEvent, eventData);
+ break;
+
+ case NFA_WRITE_CPLT_EVT: // Write completed
+ ALOGD("%s: NFA_WRITE_CPLT_EVT: status = %d", __FUNCTION__, eventData->status);
+ nativeNfcTag_doWriteStatus (eventData->status == NFA_STATUS_OK);
+ break;
+
+ case NFA_SET_TAG_RO_EVT: // Tag set as Read only
+ ALOGD("%s: NFA_SET_TAG_RO_EVT: status = %d", __FUNCTION__, eventData->status);
+ nativeNfcTag_doMakeReadonlyResult(eventData->status);
+ break;
+
+ case NFA_CE_NDEF_WRITE_START_EVT: // NDEF write started
+ ALOGD("%s: NFA_CE_NDEF_WRITE_START_EVT: status: %d", __FUNCTION__, eventData->status);
+
+ if (eventData->status != NFA_STATUS_OK)
+ ALOGE("%s: NFA_CE_NDEF_WRITE_START_EVT error: status = %d", __FUNCTION__, eventData->status);
+ break;
+
+ case NFA_CE_NDEF_WRITE_CPLT_EVT: // NDEF write completed
+ ALOGD("%s: FA_CE_NDEF_WRITE_CPLT_EVT: len = %lu", __FUNCTION__, eventData->ndef_write_cplt.len);
+ break;
+
+ case NFA_LLCP_ACTIVATED_EVT: // LLCP link is activated
+ ALOGD("%s: NFA_LLCP_ACTIVATED_EVT: is_initiator: %d remote_wks: %d, remote_lsc: %d, remote_link_miu: %d, local_link_miu: %d",
+ __FUNCTION__,
+ eventData->llcp_activated.is_initiator,
+ eventData->llcp_activated.remote_wks,
+ eventData->llcp_activated.remote_lsc,
+ eventData->llcp_activated.remote_link_miu,
+ eventData->llcp_activated.local_link_miu);
+
+ PeerToPeer::getInstance().llcpActivatedHandler (getNative(0, 0), eventData->llcp_activated);
+ break;
+
+ case NFA_LLCP_DEACTIVATED_EVT: // LLCP link is deactivated
+ ALOGD("%s: NFA_LLCP_DEACTIVATED_EVT", __FUNCTION__);
+ PeerToPeer::getInstance().llcpDeactivatedHandler (getNative(0, 0), eventData->llcp_deactivated);
+ break;
+
+ case NFA_PRESENCE_CHECK_EVT:
+ ALOGD("%s: NFA_PRESENCE_CHECK_EVT", __FUNCTION__);
+ nativeNfcTag_doPresenceCheckResult (eventData->status);
+ break;
+
+ case NFA_FORMAT_CPLT_EVT:
+ ALOGD("%s: NFA_FORMAT_CPLT_EVT: status=0x%X", __FUNCTION__, eventData->status);
+ nativeNfcTag_formatStatus (eventData->status == NFA_STATUS_OK);
+ break;
+
+ case NFA_I93_CMD_CPLT_EVT:
+ ALOGD("%s: NFA_I93_CMD_CPLT_EVT: status=0x%X", __FUNCTION__, eventData->status);
+ break;
+
+ case NFA_CE_UICC_LISTEN_CONFIGURED_EVT :
+ ALOGD("%s: NFA_CE_UICC_LISTEN_CONFIGURED_EVT : status=0x%X", __FUNCTION__, eventData->status);
+ SecureElement::getInstance().connectionEventHandler (connEvent, eventData);
+ break;
+
+ case NFA_SET_P2P_LISTEN_TECH_EVT:
+ ALOGD("%s: NFA_SET_P2P_LISTEN_TECH_EVT", __FUNCTION__);
+ PeerToPeer::getInstance().connectionEventHandler (connEvent, eventData);
+ break;
+
+ default:
+ ALOGE("%s: unknown event ????", __FUNCTION__);
+ break;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: nfcManager_initNativeStruc
+**
+** Description: Initialize variables.
+** e: JVM environment.
+** o: Java object.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+static jboolean nfcManager_initNativeStruc (JNIEnv* e, jobject o)
+{
+ nfc_jni_native_data* nat = NULL;
+ jclass cls = NULL;
+ jobject obj = NULL;
+ jfieldID f = 0;
+
+ ALOGD ("%s: enter", __FUNCTION__);
+
+ nat = (nfc_jni_native_data*)malloc(sizeof(struct nfc_jni_native_data));
+ if (nat == NULL)
+ {
+ ALOGE ("%s: fail allocate native data", __FUNCTION__);
+ return JNI_FALSE;
+ }
+
+ memset (nat, 0, sizeof(*nat));
+ e->GetJavaVM (&(nat->vm));
+ nat->env_version = e->GetVersion ();
+ nat->manager = e->NewGlobalRef (o);
+
+ cls = e->GetObjectClass (o);
+ f = e->GetFieldID (cls, "mNative", "I");
+ e->SetIntField (o, f, (jint)nat);
+
+ /* Initialize native cached references */
+ gCachedNfcManagerNotifyNdefMessageListeners = e->GetMethodID (cls,
+ "notifyNdefMessageListeners", "(Lcom/android/nfc/dhimpl/NativeNfcTag;)V");
+ gCachedNfcManagerNotifyTransactionListeners = e->GetMethodID (cls,
+ "notifyTransactionListeners", "([B)V");
+ gCachedNfcManagerNotifyLlcpLinkActivation = e->GetMethodID (cls,
+ "notifyLlcpLinkActivation", "(Lcom/android/nfc/dhimpl/NativeP2pDevice;)V");
+ gCachedNfcManagerNotifyLlcpLinkDeactivated = e->GetMethodID (cls,
+ "notifyLlcpLinkDeactivated", "(Lcom/android/nfc/dhimpl/NativeP2pDevice;)V");
+ sCachedNfcManagerNotifyTargetDeselected = e->GetMethodID (cls,
+ "notifyTargetDeselected","()V");
+ gCachedNfcManagerNotifySeFieldActivated = e->GetMethodID (cls,
+ "notifySeFieldActivated", "()V");
+ gCachedNfcManagerNotifySeFieldDeactivated = e->GetMethodID (cls,
+ "notifySeFieldDeactivated", "()V");
+ gCachedNfcManagerNotifySeListenActivated = e->GetMethodID (cls,
+ "notifySeListenActivated", "()V");
+ gCachedNfcManagerNotifySeListenDeactivated = e->GetMethodID (cls,
+ "notifySeListenDeactivated", "()V");
+
+ sCachedNfcManagerNotifySeApduReceived = e->GetMethodID(cls,
+ "notifySeApduReceived", "([B)V");
+
+ sCachedNfcManagerNotifySeMifareAccess = e->GetMethodID(cls,
+ "notifySeMifareAccess", "([B)V");
+
+ sCachedNfcManagerNotifySeEmvCardRemoval = e->GetMethodID(cls,
+ "notifySeEmvCardRemoval", "()V");
+
+ if (nfc_jni_cache_object(e,gNativeNfcTagClassName, &(nat->cached_NfcTag)) == -1)
+ {
+ ALOGE ("%s: fail cache NativeNfcTag", __FUNCTION__);
+ return JNI_FALSE;
+ }
+
+ if (nfc_jni_cache_object(e,gNativeP2pDeviceClassName, &(nat->cached_P2pDevice)) == -1)
+ {
+ ALOGE ("%s: fail cache NativeP2pDevice", __FUNCTION__);
+ return JNI_FALSE;
+ }
+
+ ALOGD ("%s: exit", __FUNCTION__);
+ return JNI_TRUE;
+}
+
+
+/*******************************************************************************
+**
+** Function: nfaDeviceManagementCallback
+**
+** Description: Receive device management events from stack.
+** dmEvent: Device-management event ID.
+** eventData: Data associated with event ID.
+**
+** Returns: None
+**
+*******************************************************************************/
+void nfaDeviceManagementCallback (UINT8 dmEvent, tNFA_DM_CBACK_DATA* eventData)
+{
+ ALOGD ("%s: enter; event=0x%X", __FUNCTION__, dmEvent);
+
+ switch (dmEvent)
+ {
+ case NFA_DM_ENABLE_EVT: /* Result of NFA_Enable */
+ {
+ SyncEventGuard guard (sNfaEnableEvent);
+ ALOGD ("%s: NFA_DM_ENABLE_EVT; status=0x%X",
+ __FUNCTION__, eventData->status);
+ sIsNfaEnabled = eventData->status == NFA_STATUS_OK;
+ sIsDisabling = false;
+ sNfaEnableEvent.notifyOne ();
+ }
+ break;
+
+ case NFA_DM_DISABLE_EVT: /* Result of NFA_Disable */
+ {
+ SyncEventGuard guard (sNfaDisableEvent);
+ ALOGD ("%s: NFA_DM_DISABLE_EVT", __FUNCTION__);
+ sIsNfaEnabled = false;
+ sIsDisabling = false;
+ sNfaDisableEvent.notifyOne ();
+ }
+ break;
+
+ case NFA_DM_SET_CONFIG_EVT: //result of NFA_SetConfig
+ ALOGD ("%s: NFA_DM_SET_CONFIG_EVT", __FUNCTION__);
+ {
+ SyncEventGuard guard (sNfaSetConfigEvent);
+ sNfaSetConfigEvent.notifyOne();
+ }
+ break;
+
+ case NFA_DM_GET_CONFIG_EVT: /* Result of NFA_GetConfig */
+ ALOGD ("%s: NFA_DM_GET_CONFIG_EVT", __FUNCTION__);
+ break;
+
+ case NFA_DM_RF_FIELD_EVT:
+ ALOGD ("%s: NFA_DM_RF_FIELD_EVT; status=0x%X; field status=%u", __FUNCTION__,
+ eventData->rf_field.status, eventData->rf_field.rf_field_status);
+
+ if (!sIsDisabling && eventData->rf_field.status == NFA_STATUS_OK)
+ SecureElement::getInstance().notifyRfFieldEvent (eventData->rf_field.rf_field_status == NFA_DM_RF_FIELD_ON);
+ break;
+
+ case NFA_DM_NFCC_TRANSPORT_ERR_EVT:
+ case NFA_DM_NFCC_TIMEOUT_EVT:
+ {
+ if (dmEvent == NFA_DM_NFCC_TIMEOUT_EVT)
+ ALOGD ("%s: NFA_DM_NFCC_TIMEOUT_EVT; abort all outstanding operations", __FUNCTION__);
+ else
+ ALOGD ("%s: NFA_DM_NFCC_TRANSPORT_ERR_EVT; abort all outstanding operations", __FUNCTION__);
+
+ nativeNfcTag_abortWaits();
+ NfcTag::getInstance().abort ();
+ sAbortConnlessWait = true;
+ nativeLlcpConnectionlessSocket_abortWait();
+ {
+ ALOGD ("%s: aborting sNfaEnableDisablePollingEvent", __FUNCTION__);
+ SyncEventGuard guard (sNfaEnableDisablePollingEvent);
+ sNfaEnableDisablePollingEvent.notifyOne();
+ }
+ {
+ ALOGD ("%s: aborting sNfaEnableEvent", __FUNCTION__);
+ SyncEventGuard guard (sNfaEnableEvent);
+ sNfaEnableEvent.notifyOne();
+ }
+ {
+ ALOGD ("%s: aborting sNfaDisableEvent", __FUNCTION__);
+ SyncEventGuard guard (sNfaDisableEvent);
+ sNfaDisableEvent.notifyOne();
+ }
+ sDiscoveryEnabled = false;
+ PowerSwitch::getInstance ().abort ();
+
+ if (!sIsDisabling && sIsNfaEnabled)
+ {
+ NFA_Disable(FALSE);
+ sIsDisabling = true;
+ }
+ else
+ {
+ sIsNfaEnabled = false;
+ sIsDisabling = false;
+ }
+ PowerSwitch::getInstance ().initialize (PowerSwitch::UNKNOWN_LEVEL);
+ ALOGD ("%s: aborted all waiting events", __FUNCTION__);
+ }
+ break;
+
+ case NFA_DM_PWR_MODE_CHANGE_EVT:
+ PowerSwitch::getInstance ().deviceManagementCallback (dmEvent, eventData);
+ break;
+
+ default:
+ ALOGD ("%s: unhandled event", __FUNCTION__);
+ break;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: nfcManager_doInitialize
+**
+** Description: Turn on NFC.
+** e: JVM environment.
+** o: Java object.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+static jboolean nfcManager_doInitialize (JNIEnv* e, jobject o)
+{
+ ALOGD ("%s: enter; NCI_VERSION=0x%02X", __FUNCTION__, NCI_VERSION);
+ tNFA_STATUS stat = NFA_STATUS_OK;
+
+ if (sIsNfaEnabled)
+ {
+ ALOGD ("%s: already enabled", __FUNCTION__);
+ goto TheEnd;
+ }
+
+ PowerSwitch::getInstance ().initialize (PowerSwitch::FULL_POWER);
+
+ {
+ unsigned long num = 0;
+
+ NfcAdaptation& theInstance = NfcAdaptation::GetInstance();
+ theInstance.Initialize(); //start GKI, NCI task, NFC task
+
+ {
+ SyncEventGuard guard (sNfaEnableEvent);
+ tHAL_NFC_ENTRY* halFuncEntries = theInstance.GetHalEntryFuncs ();
+
+ NFA_Init (halFuncEntries);
+
+ stat = NFA_Enable (nfaDeviceManagementCallback, nfaConnectionCallback);
+ if (stat == NFA_STATUS_OK)
+ {
+ num = initializeGlobalAppLogLevel ();
+ CE_SetTraceLevel (num);
+ LLCP_SetTraceLevel (num);
+ NFC_SetTraceLevel (num);
+ RW_SetTraceLevel (num);
+ NFA_SetTraceLevel (num);
+ NFA_ChoSetTraceLevel (num);
+ NFA_P2pSetTraceLevel (num);
+ NFA_SnepSetTraceLevel (num);
+ sNfaEnableEvent.wait(); //wait for NFA command to finish
+ }
+ }
+
+ if (stat == NFA_STATUS_OK)
+ {
+ //sIsNfaEnabled indicates whether stack started successfully
+ if (sIsNfaEnabled)
+ {
+ SecureElement::getInstance().initialize (getNative(e, o));
+ nativeNfcTag_registerNdefTypeHandler ();
+ NfcTag::getInstance().initialize (getNative(e, o));
+ PeerToPeer::getInstance().initialize ();
+ PeerToPeer::getInstance().handleNfcOnOff (true);
+
+ /////////////////////////////////////////////////////////////////////////////////
+ // Add extra configuration here (work-arounds, etc.)
+
+ struct nfc_jni_native_data *nat = getNative(e, o);
+
+ if ( nat )
+ {
+ if (GetNumValue(NAME_POLLING_TECH_MASK, &num, sizeof(num)))
+ nat->tech_mask = num;
+ else
+ nat->tech_mask = DEFAULT_TECH_MASK;
+
+ ALOGD ("%s: tag polling tech mask=0x%X", __FUNCTION__, nat->tech_mask);
+ }
+
+ // Always restore LPTD Configuration to the stack default.
+ if (sOriginalLptdCfg != NULL)
+ p_nfa_dm_lptd_cfg = sOriginalLptdCfg;
+
+ // if this value exists, set polling interval.
+ if (GetNumValue(NAME_NFA_DM_DISC_DURATION_POLL, &num, sizeof(num)))
+ NFA_SetRfDiscoveryDuration(num);
+
+ // Do custom NFCA startup configuration.
+ doStartupConfig();
+ goto TheEnd;
+ }
+ }
+
+ ALOGE ("%s: fail nfa enable; error=0x%X", __FUNCTION__, stat);
+
+ if (sIsNfaEnabled)
+ stat = NFA_Disable (FALSE /* ungraceful */);
+
+ theInstance.Finalize();
+ }
+
+TheEnd:
+ if (sIsNfaEnabled)
+ PowerSwitch::getInstance ().setLevel (PowerSwitch::LOW_POWER);
+ ALOGD ("%s: exit", __FUNCTION__);
+ return sIsNfaEnabled ? JNI_TRUE : JNI_FALSE;
+}
+
+
+/*******************************************************************************
+**
+** Function: nfcManager_enableDiscovery
+**
+** Description: Start polling and listening for devices.
+** e: JVM environment.
+** o: Java object.
+** mode: Not used.
+**
+** Returns: None
+**
+*******************************************************************************/
+static void nfcManager_enableDiscovery (JNIEnv* e, jobject o)
+{
+ tNFA_TECHNOLOGY_MASK tech_mask = DEFAULT_TECH_MASK;
+ struct nfc_jni_native_data *nat = getNative(e, o);
+
+ if (nat)
+ tech_mask = (tNFA_TECHNOLOGY_MASK)nat->tech_mask;
+
+ ALOGD ("%s: enter; tech_mask = %02x", __FUNCTION__, tech_mask);
+
+ if (sDiscoveryEnabled)
+ {
+ ALOGE ("%s: already polling", __FUNCTION__);
+ return;
+ }
+
+ tNFA_STATUS stat = NFA_STATUS_OK;
+
+ ALOGD ("%s: sIsSecElemSelected=%u", __FUNCTION__, sIsSecElemSelected);
+
+ PowerSwitch::getInstance ().setLevel (PowerSwitch::FULL_POWER);
+
+ if (sRfEnabled) {
+ // Stop RF discovery to reconfigure
+ startRfDiscovery(false);
+ }
+
+ {
+ SyncEventGuard guard (sNfaEnableDisablePollingEvent);
+ stat = NFA_EnablePolling (tech_mask);
+ if (stat == NFA_STATUS_OK)
+ {
+ ALOGD ("%s: wait for enable event", __FUNCTION__);
+ sDiscoveryEnabled = true;
+ sNfaEnableDisablePollingEvent.wait (); //wait for NFA_POLL_ENABLED_EVT
+ ALOGD ("%s: got enabled event", __FUNCTION__);
+ }
+ else
+ {
+ ALOGE ("%s: fail enable discovery; error=0x%X", __FUNCTION__, stat);
+ }
+ }
+
+ // Start P2P listening if tag polling was enabled or the mask was 0.
+ if (sDiscoveryEnabled || (tech_mask == 0))
+ {
+ ALOGD ("%s: Enable p2pListening", __FUNCTION__);
+ PeerToPeer::getInstance().enableP2pListening (true);
+
+ //if NFC service has deselected the sec elem, then apply default routes
+ if (!sIsSecElemSelected)
+ stat = SecureElement::getInstance().routeToDefault ();
+ }
+
+ // Actually start discovery.
+ startRfDiscovery (true);
+
+ PowerSwitch::getInstance ().setModeOn (PowerSwitch::DISCOVERY);
+
+ ALOGD ("%s: exit", __FUNCTION__);
+}
+
+
+/*******************************************************************************
+**
+** Function: nfcManager_disableDiscovery
+**
+** Description: Stop polling and listening for devices.
+** e: JVM environment.
+** o: Java object.
+**
+** Returns: None
+**
+*******************************************************************************/
+void nfcManager_disableDiscovery (JNIEnv* e, jobject o)
+{
+ tNFA_STATUS status = NFA_STATUS_OK;
+ ALOGD ("%s: enter;", __FUNCTION__);
+
+ pn544InteropAbortNow ();
+ if (sDiscoveryEnabled == false)
+ {
+ ALOGD ("%s: already disabled", __FUNCTION__);
+ goto TheEnd;
+ }
+
+ // Stop RF Discovery.
+ startRfDiscovery (false);
+
+ if (sDiscoveryEnabled)
+ {
+ SyncEventGuard guard (sNfaEnableDisablePollingEvent);
+ status = NFA_DisablePolling ();
+ if (status == NFA_STATUS_OK)
+ {
+ sDiscoveryEnabled = false;
+ sNfaEnableDisablePollingEvent.wait (); //wait for NFA_POLL_DISABLED_EVT
+ }
+ else
+ ALOGE ("%s: Failed to disable polling; error=0x%X", __FUNCTION__, status);
+ }
+
+ PeerToPeer::getInstance().enableP2pListening (false);
+
+ //if nothing is active after this, then tell the controller to power down
+ if (! PowerSwitch::getInstance ().setModeOff (PowerSwitch::DISCOVERY))
+ PowerSwitch::getInstance ().setLevel (PowerSwitch::LOW_POWER);
+
+TheEnd:
+ ALOGD ("%s: exit", __FUNCTION__);
+}
+
+/*******************************************************************************
+**
+** Function nfc_jni_cache_object_local
+**
+** Description Allocates a java object and calls it's constructor
+**
+** Returns -1 on failure, 0 on success
+**
+*******************************************************************************/
+int nfc_jni_cache_object_local (JNIEnv *e, const char *className, jobject *cachedObj)
+{
+ jclass cls = NULL;
+ jobject obj = NULL;
+ jmethodID ctor = 0;
+
+ cls = e->FindClass (className);
+ if(cls == NULL)
+ {
+ ALOGE ("%s: find class error", __FUNCTION__);
+ return -1;
+ }
+
+ ctor = e->GetMethodID (cls, "<init>", "()V");
+ obj = e->NewObject (cls, ctor);
+ if (obj == NULL)
+ {
+ ALOGE ("%s: create object error", __FUNCTION__);
+ return -1;
+ }
+
+ *cachedObj = e->NewLocalRef (obj);
+ if (*cachedObj == NULL)
+ {
+ e->DeleteLocalRef (obj);
+ ALOGE ("%s: global ref error", __FUNCTION__);
+ return -1;
+ }
+ e->DeleteLocalRef (obj);
+ return 0;
+}
+
+
+/*******************************************************************************
+**
+** Function: nfcManager_doCreateLlcpServiceSocket
+**
+** Description: Create a new LLCP server socket.
+** e: JVM environment.
+** o: Java object.
+** nSap: Service access point.
+** sn: Service name
+** miu: Maximum information unit.
+** rw: Receive window size.
+** linearBufferLength: Max buffer size.
+**
+** Returns: NativeLlcpServiceSocket Java object.
+**
+*******************************************************************************/
+static jobject nfcManager_doCreateLlcpServiceSocket (JNIEnv* e, jobject o, jint nSap, jstring sn, jint miu, jint rw, jint linearBufferLength)
+{
+ bool stat = false;
+ jobject serviceSocket = NULL;
+ jclass clsNativeLlcpServiceSocket = NULL;
+ jfieldID f = 0;
+ PeerToPeer::tJNI_HANDLE jniHandle = PeerToPeer::getInstance().getNewJniHandle ();
+ const char* serviceName = e->GetStringUTFChars (sn, JNI_FALSE); //convert jstring, which is unicode, into char*
+ std::string serviceName2 (serviceName);
+
+ e->ReleaseStringUTFChars (sn, serviceName); //free the string
+ ALOGD ("%s: enter: sap=%i; name=%s; miu=%i; rw=%i; buffLen=%i", __FUNCTION__, nSap, serviceName2.c_str(), miu, rw, linearBufferLength);
+
+ /* Create new NativeLlcpServiceSocket object */
+ if (nfc_jni_cache_object(e, gNativeLlcpServiceSocketClassName, &(serviceSocket)) == -1)
+ {
+ ALOGE ("%s: Llcp socket object creation error", __FUNCTION__);
+ return NULL;
+ }
+
+ /* Get NativeLlcpServiceSocket class object */
+ clsNativeLlcpServiceSocket = e->GetObjectClass (serviceSocket);
+ if (e->ExceptionCheck())
+ {
+ e->ExceptionClear();
+ ALOGE("%s: Llcp Socket get object class error", __FUNCTION__);
+ return NULL;
+ }
+
+ if (!PeerToPeer::getInstance().registerServer (jniHandle, serviceName2.c_str()))
+ {
+ ALOGE("%s: RegisterServer error", __FUNCTION__);
+ return NULL;
+ }
+
+ /* Set socket handle to be the same as the NfaHandle*/
+ f = e->GetFieldID (clsNativeLlcpServiceSocket, "mHandle", "I");
+ e->SetIntField (serviceSocket, f, (jint) jniHandle);
+ ALOGD ("%s: socket Handle = 0x%X", __FUNCTION__, jniHandle);
+
+ /* Set socket linear buffer length */
+ f = e->GetFieldID (clsNativeLlcpServiceSocket, "mLocalLinearBufferLength", "I");
+ e->SetIntField (serviceSocket, f,(jint)linearBufferLength);
+ ALOGD ("%s: buffer length = %d", __FUNCTION__, linearBufferLength);
+
+ /* Set socket MIU */
+ f = e->GetFieldID (clsNativeLlcpServiceSocket, "mLocalMiu", "I");
+ e->SetIntField (serviceSocket, f,(jint)miu);
+ ALOGD ("%s: MIU = %d", __FUNCTION__, miu);
+
+ /* Set socket RW */
+ f = e->GetFieldID (clsNativeLlcpServiceSocket, "mLocalRw", "I");
+ e->SetIntField (serviceSocket, f,(jint)rw);
+ ALOGD ("%s: RW = %d", __FUNCTION__, rw);
+
+ sLastError = 0;
+ ALOGD ("%s: exit", __FUNCTION__);
+ return serviceSocket;
+}
+
+
+/*******************************************************************************
+**
+** Function: nfcManager_doGetLastError
+**
+** Description: Get the last error code.
+** e: JVM environment.
+** o: Java object.
+**
+** Returns: Last error code.
+**
+*******************************************************************************/
+static jint nfcManager_doGetLastError(JNIEnv* e, jobject o)
+{
+ ALOGD ("%s: last error=%i", __FUNCTION__, sLastError);
+ return sLastError;
+}
+
+
+/*******************************************************************************
+**
+** Function: nfcManager_doDeinitialize
+**
+** Description: Turn off NFC.
+** e: JVM environment.
+** o: Java object.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+static jboolean nfcManager_doDeinitialize (JNIEnv* e, jobject o)
+{
+ ALOGD ("%s: enter", __FUNCTION__);
+
+ sIsDisabling = true;
+ pn544InteropAbortNow ();
+ SecureElement::getInstance().finalize ();
+
+ if (sIsNfaEnabled)
+ {
+ SyncEventGuard guard (sNfaDisableEvent);
+ tNFA_STATUS stat = NFA_Disable (TRUE /* graceful */);
+ if (stat == NFA_STATUS_OK)
+ {
+ ALOGD ("%s: wait for completion", __FUNCTION__);
+ sNfaDisableEvent.wait (); //wait for NFA command to finish
+ PeerToPeer::getInstance ().handleNfcOnOff (false);
+ }
+ else
+ {
+ ALOGE ("%s: fail disable; error=0x%X", __FUNCTION__, stat);
+ }
+ }
+ nativeNfcTag_abortWaits();
+ NfcTag::getInstance().abort ();
+ sAbortConnlessWait = true;
+ nativeLlcpConnectionlessSocket_abortWait();
+ sIsNfaEnabled = false;
+ sDiscoveryEnabled = false;
+ sIsDisabling = false;
+ sIsSecElemSelected = false;
+
+ {
+ //unblock NFA_EnablePolling() and NFA_DisablePolling()
+ SyncEventGuard guard (sNfaEnableDisablePollingEvent);
+ sNfaEnableDisablePollingEvent.notifyOne ();
+ }
+
+ NfcAdaptation& theInstance = NfcAdaptation::GetInstance();
+ theInstance.Finalize();
+
+ ALOGD ("%s: exit", __FUNCTION__);
+ return JNI_TRUE;
+}
+
+
+/*******************************************************************************
+**
+** Function: nfcManager_doCreateLlcpSocket
+**
+** Description: Create a LLCP connection-oriented socket.
+** e: JVM environment.
+** o: Java object.
+** nSap: Service access point.
+** miu: Maximum information unit.
+** rw: Receive window size.
+** linearBufferLength: Max buffer size.
+**
+** Returns: NativeLlcpSocket Java object.
+**
+*******************************************************************************/
+static jobject nfcManager_doCreateLlcpSocket (JNIEnv* e, jobject o, jint nSap, jint miu, jint rw, jint linearBufferLength)
+{
+ ALOGD ("%s: enter; sap=%d; miu=%d; rw=%d; buffer len=%d", __FUNCTION__, nSap, miu, rw, linearBufferLength);
+ jobject clientSocket = NULL;
+ jclass clsNativeLlcpSocket;
+ jfieldID f;
+ PeerToPeer::tJNI_HANDLE jniHandle = PeerToPeer::getInstance().getNewJniHandle ();
+ bool stat = false;
+
+ stat = PeerToPeer::getInstance().createClient (jniHandle, miu, rw);
+
+ /* Create new NativeLlcpSocket object */
+ if (nfc_jni_cache_object_local(e, gNativeLlcpSocketClassName, &(clientSocket)) == -1)
+ {
+ ALOGE ("%s: fail Llcp socket creation", __FUNCTION__);
+ goto TheEnd;
+ }
+
+ /* Get NativeConnectionless class object */
+ clsNativeLlcpSocket = e->GetObjectClass (clientSocket);
+ if (e->ExceptionCheck())
+ {
+ e->ExceptionClear();
+ ALOGE ("%s: fail get class object", __FUNCTION__);
+ goto TheEnd;
+ }
+
+ /* Set socket SAP */
+ f = e->GetFieldID (clsNativeLlcpSocket, "mSap", "I");
+ e->SetIntField (clientSocket, f, (jint) nSap);
+
+ /* Set socket handle */
+ f = e->GetFieldID (clsNativeLlcpSocket, "mHandle", "I");
+ e->SetIntField (clientSocket, f, (jint) jniHandle);
+
+ /* Set socket MIU */
+ f = e->GetFieldID (clsNativeLlcpSocket, "mLocalMiu", "I");
+ e->SetIntField (clientSocket, f, (jint) miu);
+
+ /* Set socket RW */
+ f = e->GetFieldID (clsNativeLlcpSocket, "mLocalRw", "I");
+ e->SetIntField (clientSocket, f, (jint) rw);
+
+TheEnd:
+ ALOGD ("%s: exit", __FUNCTION__);
+ return clientSocket;
+}
+
+
+/*******************************************************************************
+**
+** Function: nfcManager_doCreateLlcpConnectionlessSocket
+**
+** Description: Create a connection-less socket.
+** e: JVM environment.
+** o: Java object.
+** nSap: Service access point.
+** sn: Service name.
+**
+** Returns: NativeLlcpConnectionlessSocket Java object.
+**
+*******************************************************************************/
+static jobject nfcManager_doCreateLlcpConnectionlessSocket (JNIEnv *e, jobject o, jint nSap, jstring sn)
+{
+ ALOGD ("%s: nSap=0x%X", __FUNCTION__, nSap);
+ return NULL;
+}
+
+
+/*******************************************************************************
+**
+** Function: nfcManager_doGetSecureElementList
+**
+** Description: Get a list of secure element handles.
+** e: JVM environment.
+** o: Java object.
+**
+** Returns: List of secure element handles.
+**
+*******************************************************************************/
+static jintArray nfcManager_doGetSecureElementList(JNIEnv *e, jobject o)
+{
+ ALOGD ("%s", __FUNCTION__);
+ return SecureElement::getInstance().getListOfEeHandles (e);
+}
+
+
+/*******************************************************************************
+**
+** Function: nfcManager_doSelectSecureElement
+**
+** Description: NFC controller starts routing data in listen mode.
+** e: JVM environment.
+** o: Java object.
+**
+** Returns: None
+**
+*******************************************************************************/
+static void nfcManager_doSelectSecureElement(JNIEnv *e, jobject o)
+{
+ ALOGD ("%s: enter", __FUNCTION__);
+ bool stat = true;
+
+ PowerSwitch::getInstance ().setLevel (PowerSwitch::FULL_POWER);
+
+ if (sRfEnabled) {
+ // Stop RF Discovery if we were polling
+ startRfDiscovery (false);
+ }
+
+ if (sIsSecElemSelected)
+ {
+ ALOGD ("%s: already selected", __FUNCTION__);
+ goto TheEnd;
+ }
+
+ stat = SecureElement::getInstance().activate (0xABCDEF);
+ if (stat)
+ SecureElement::getInstance().routeToSecureElement ();
+ sIsSecElemSelected = true;
+
+TheEnd:
+ startRfDiscovery (true);
+
+ PowerSwitch::getInstance ().setModeOn (PowerSwitch::SE_ROUTING);
+
+ ALOGD ("%s: exit", __FUNCTION__);
+}
+
+
+/*******************************************************************************
+**
+** Function: nfcManager_doDeselectSecureElement
+**
+** Description: NFC controller stops routing data in listen mode.
+** e: JVM environment.
+** o: Java object.
+**
+** Returns: None
+**
+*******************************************************************************/
+static void nfcManager_doDeselectSecureElement(JNIEnv *e, jobject o)
+{
+ ALOGD ("%s: enter", __FUNCTION__);
+ bool stat = false;
+
+ if (! sIsSecElemSelected)
+ {
+ ALOGE ("%s: already deselected", __FUNCTION__);
+ goto TheEnd;
+ }
+
+ if (PowerSwitch::getInstance ().getLevel() == PowerSwitch::LOW_POWER)
+ {
+ ALOGD ("%s: do not deselect while power is OFF", __FUNCTION__);
+ sIsSecElemSelected = false;
+ goto TheEnd;
+ }
+
+ stat = SecureElement::getInstance().routeToDefault ();
+ sIsSecElemSelected = false;
+
+ //if controller is not routing to sec elems AND there is no pipe connected,
+ //then turn off the sec elems
+ if (SecureElement::getInstance().isBusy() == false)
+ SecureElement::getInstance().deactivate (0xABCDEF);
+
+TheEnd:
+ //if nothing is active after this, then tell the controller to power down
+ if (! PowerSwitch::getInstance ().setModeOff (PowerSwitch::SE_ROUTING))
+ PowerSwitch::getInstance ().setLevel (PowerSwitch::LOW_POWER);
+
+ ALOGD ("%s: exit", __FUNCTION__);
+}
+
+
+/*******************************************************************************
+**
+** Function: isPeerToPeer
+**
+** Description: Whether the activation data indicates the peer supports NFC-DEP.
+** activated: Activation data.
+**
+** Returns: True if the peer supports NFC-DEP.
+**
+*******************************************************************************/
+static bool isPeerToPeer (tNFA_ACTIVATED& activated)
+{
+ return activated.activate_ntf.protocol == NFA_PROTOCOL_NFC_DEP;
+}
+
+/*******************************************************************************
+**
+** Function: isListenMode
+**
+** Description: Indicates whether the activation data indicates it is
+** listen mode.
+**
+** Returns: True if this listen mode.
+**
+*******************************************************************************/
+static bool isListenMode(tNFA_ACTIVATED& activated)
+{
+ return ((NFC_DISCOVERY_TYPE_LISTEN_A == activated.activate_ntf.rf_tech_param.mode)
+ || (NFC_DISCOVERY_TYPE_LISTEN_B == activated.activate_ntf.rf_tech_param.mode)
+ || (NFC_DISCOVERY_TYPE_LISTEN_F == activated.activate_ntf.rf_tech_param.mode)
+ || (NFC_DISCOVERY_TYPE_LISTEN_A_ACTIVE == activated.activate_ntf.rf_tech_param.mode)
+ || (NFC_DISCOVERY_TYPE_LISTEN_F_ACTIVE == activated.activate_ntf.rf_tech_param.mode)
+ || (NFC_DISCOVERY_TYPE_LISTEN_ISO15693 == activated.activate_ntf.rf_tech_param.mode)
+ || (NFC_DISCOVERY_TYPE_LISTEN_B_PRIME == activated.activate_ntf.rf_tech_param.mode));
+}
+
+/*******************************************************************************
+**
+** Function: nfcManager_doCheckLlcp
+**
+** Description: Not used.
+**
+** Returns: True
+**
+*******************************************************************************/
+static jboolean nfcManager_doCheckLlcp(JNIEnv *e, jobject o)
+{
+ ALOGD("%s", __FUNCTION__);
+ return JNI_TRUE;
+}
+
+
+/*******************************************************************************
+**
+** Function: nfcManager_doActivateLlcp
+**
+** Description: Not used.
+**
+** Returns: True
+**
+*******************************************************************************/
+static jboolean nfcManager_doActivateLlcp(JNIEnv *e, jobject o)
+{
+ ALOGD("%s", __FUNCTION__);
+ return JNI_TRUE;
+}
+
+
+/*******************************************************************************
+**
+** Function: nfcManager_doAbort
+**
+** Description: Not used.
+**
+** Returns: None
+**
+*******************************************************************************/
+static void nfcManager_doAbort(JNIEnv *e, jobject o)
+{
+ ALOGE("%s: abort()", __FUNCTION__);
+ abort();
+}
+
+
+/*******************************************************************************
+**
+** Function: nfcManager_doDownload
+**
+** Description: Not used.
+**
+** Returns: True
+**
+*******************************************************************************/
+static jboolean nfcManager_doDownload(JNIEnv *e, jobject o)
+{
+ ALOGD("%s", __FUNCTION__);
+ return JNI_TRUE;
+}
+
+
+/*******************************************************************************
+**
+** Function: nfcManager_doResetTimeouts
+**
+** Description: Not used.
+**
+** Returns: None
+**
+*******************************************************************************/
+static void nfcManager_doResetTimeouts(JNIEnv *e, jobject o)
+{
+ ALOGD ("%s: %d millisec", __FUNCTION__, DEFAULT_GENERAL_TRANS_TIMEOUT);
+ gGeneralTransceiveTimeout = DEFAULT_GENERAL_TRANS_TIMEOUT;
+}
+
+
+/*******************************************************************************
+**
+** Function: nfcManager_doSetTimeout
+**
+** Description: Set timeout value.
+** e: JVM environment.
+** o: Java object.
+** timeout: Timeout value.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+static bool nfcManager_doSetTimeout(JNIEnv *e, jobject o, jint tech, jint timeout)
+{
+ if (timeout <= 0)
+ {
+ ALOGE("%s: Timeout must be positive.",__FUNCTION__);
+ return false;
+ }
+
+ ALOGD ("%s: timeout=%d", __FUNCTION__, timeout);
+ gGeneralTransceiveTimeout = timeout;
+ return true;
+}
+
+
+/*******************************************************************************
+**
+** Function: nfcManager_doGetTimeout
+**
+** Description: Get timeout value.
+** e: JVM environment.
+** o: Java object.
+** tech: Not used.
+**
+** Returns: Timeout value.
+**
+*******************************************************************************/
+static jint nfcManager_doGetTimeout(JNIEnv *e, jobject o, jint tech)
+{
+ ALOGD ("%s: timeout=%d", __FUNCTION__, gGeneralTransceiveTimeout);
+ return gGeneralTransceiveTimeout;
+}
+
+
+/*******************************************************************************
+**
+** Function: nfcManager_doDump
+**
+** Description: Not used.
+** e: JVM environment.
+** o: Java object.
+**
+** Returns: Text dump.
+**
+*******************************************************************************/
+static jstring nfcManager_doDump(JNIEnv *e, jobject o)
+{
+ char buffer[100];
+ snprintf(buffer, sizeof(buffer), "libnfc llc error_count=%u", /*libnfc_llc_error_count*/ 0);
+ return e->NewStringUTF(buffer);
+}
+
+
+/*******************************************************************************
+**
+** Function: nfcManager_doSetP2pInitiatorModes
+**
+** Description: Set P2P initiator's activation modes.
+** e: JVM environment.
+** o: Java object.
+** modes: Active and/or passive modes. The values are specified
+** in external/libnfc-nxp/inc/phNfcTypes.h. See
+** enum phNfc_eP2PMode_t.
+**
+** Returns: None.
+**
+*******************************************************************************/
+static void nfcManager_doSetP2pInitiatorModes (JNIEnv *e, jobject o, jint modes)
+{
+ ALOGD ("%s: modes=0x%X", __FUNCTION__, modes);
+ struct nfc_jni_native_data *nat = getNative(e, o);
+
+ tNFA_TECHNOLOGY_MASK mask = 0;
+ if (modes & 0x01) mask |= NFA_TECHNOLOGY_MASK_A;
+ if (modes & 0x02) mask |= NFA_TECHNOLOGY_MASK_F;
+ if (modes & 0x04) mask |= NFA_TECHNOLOGY_MASK_F;
+ if (modes & 0x08) mask |= NFA_TECHNOLOGY_MASK_A_ACTIVE;
+ if (modes & 0x10) mask |= NFA_TECHNOLOGY_MASK_F_ACTIVE;
+ if (modes & 0x20) mask |= NFA_TECHNOLOGY_MASK_F_ACTIVE;
+ nat->tech_mask = mask;
+
+ //this function is not called by the NFC service nor exposed by public API.
+}
+
+
+/*******************************************************************************
+**
+** Function: nfcManager_doSetP2pTargetModes
+**
+** Description: Set P2P target's activation modes.
+** e: JVM environment.
+** o: Java object.
+** modes: Active and/or passive modes.
+**
+** Returns: None.
+**
+*******************************************************************************/
+static void nfcManager_doSetP2pTargetModes (JNIEnv *e, jobject o, jint modes)
+{
+ ALOGD ("%s: modes=0x%X", __FUNCTION__, modes);
+ // Map in the right modes
+ tNFA_TECHNOLOGY_MASK mask = 0;
+ if (modes & 0x01) mask |= NFA_TECHNOLOGY_MASK_A;
+ if (modes & 0x02) mask |= NFA_TECHNOLOGY_MASK_F;
+ if (modes & 0x04) mask |= NFA_TECHNOLOGY_MASK_F;
+ if (modes & 0x08) mask |= NFA_TECHNOLOGY_MASK_A_ACTIVE | NFA_TECHNOLOGY_MASK_F_ACTIVE;
+
+ PeerToPeer::getInstance().setP2pListenMask(mask);
+ //this function is not called by the NFC service nor exposed by public API.
+}
+
+/*****************************************************************************
+**
+** JNI functions for android-4.0.1_r1
+**
+*****************************************************************************/
+static JNINativeMethod gMethods[] =
+{
+ {"doDownload", "()Z",
+ (void *)nfcManager_doDownload},
+
+ {"initializeNativeStructure", "()Z",
+ (void*) nfcManager_initNativeStruc},
+
+ {"doInitialize", "()Z",
+ (void*) nfcManager_doInitialize},
+
+ {"doDeinitialize", "()Z",
+ (void*) nfcManager_doDeinitialize},
+
+ {"enableDiscovery", "()V",
+ (void*) nfcManager_enableDiscovery},
+
+ {"doGetSecureElementList", "()[I",
+ (void *)nfcManager_doGetSecureElementList},
+
+ {"doSelectSecureElement", "()V",
+ (void *)nfcManager_doSelectSecureElement},
+
+ {"doDeselectSecureElement", "()V",
+ (void *)nfcManager_doDeselectSecureElement},
+
+ {"doCheckLlcp", "()Z",
+ (void *)nfcManager_doCheckLlcp},
+
+ {"doActivateLlcp", "()Z",
+ (void *)nfcManager_doActivateLlcp},
+
+ {"doCreateLlcpConnectionlessSocket", "(ILjava/lang/String;)Lcom/android/nfc/dhimpl/NativeLlcpConnectionlessSocket;",
+ (void *)nfcManager_doCreateLlcpConnectionlessSocket},
+
+ {"doCreateLlcpServiceSocket", "(ILjava/lang/String;III)Lcom/android/nfc/dhimpl/NativeLlcpServiceSocket;",
+ (void*) nfcManager_doCreateLlcpServiceSocket},
+
+ {"doCreateLlcpSocket", "(IIII)Lcom/android/nfc/dhimpl/NativeLlcpSocket;",
+ (void*) nfcManager_doCreateLlcpSocket},
+
+ {"doGetLastError", "()I",
+ (void*) nfcManager_doGetLastError},
+
+ {"disableDiscovery", "()V",
+ (void*) nfcManager_disableDiscovery},
+
+ {"doSetTimeout", "(II)Z",
+ (void *)nfcManager_doSetTimeout},
+
+ {"doGetTimeout", "(I)I",
+ (void *)nfcManager_doGetTimeout},
+
+ {"doResetTimeouts", "()V",
+ (void *)nfcManager_doResetTimeouts},
+
+ {"doAbort", "()V",
+ (void *)nfcManager_doAbort},
+
+ {"doSetP2pInitiatorModes", "(I)V",
+ (void *)nfcManager_doSetP2pInitiatorModes},
+
+ {"doSetP2pTargetModes", "(I)V",
+ (void *)nfcManager_doSetP2pTargetModes},
+
+ {"doDump", "()Ljava/lang/String;",
+ (void *)nfcManager_doDump},
+};
+
+
+/*******************************************************************************
+**
+** Function: register_com_android_nfc_NativeNfcManager
+**
+** Description: Regisgter JNI functions with Java Virtual Machine.
+** e: Environment of JVM.
+**
+** Returns: Status of registration.
+**
+*******************************************************************************/
+int register_com_android_nfc_NativeNfcManager (JNIEnv *e)
+{
+ ALOGD ("%s: enter", __FUNCTION__);
+ PowerSwitch::getInstance ().initialize (PowerSwitch::UNKNOWN_LEVEL);
+ ALOGD ("%s: exit", __FUNCTION__);
+ return jniRegisterNativeMethods (e, gNativeNfcManagerClassName, gMethods, NELEM (gMethods));
+}
+
+
+/*******************************************************************************
+**
+** Function: startRfDiscovery
+**
+** Description: Ask stack to start polling and listening for devices.
+** isStart: Whether to start.
+**
+** Returns: None
+**
+*******************************************************************************/
+void startRfDiscovery(bool isStart)
+{
+ tNFA_STATUS status = NFA_STATUS_FAILED;
+
+ ALOGD ("%s: is start=%d", __FUNCTION__, isStart);
+ SyncEventGuard guard (sNfaEnableDisablePollingEvent);
+ status = isStart ? NFA_StartRfDiscovery () : NFA_StopRfDiscovery ();
+ if (status == NFA_STATUS_OK)
+ {
+ sNfaEnableDisablePollingEvent.wait (); //wait for NFA_RF_DISCOVERY_xxxx_EVT
+ sRfEnabled = isStart;
+ }
+ else
+ {
+ ALOGE ("%s: Failed to start/stop RF discovery; error=0x%X", __FUNCTION__, status);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: doStartupConfig
+**
+** Description: Configure the NFC controller.
+**
+** Returns: None
+**
+*******************************************************************************/
+void doStartupConfig()
+{
+ unsigned long num = 0;
+ struct nfc_jni_native_data *nat = getNative(0, 0);
+ tNFA_STATUS stat = NFA_STATUS_FAILED;
+
+ // Enable the "RC workaround" to allow our stack/firmware to work with a retail
+ // Nexus S that causes IOP issues. Only enable if value exists and set to 1.
+ if (GetNumValue(NAME_USE_NXP_P2P_RC_WORKAROUND, &num, sizeof(num)) && (num == 1))
+ {
+#if (NCI_VERSION > NCI_VERSION_20791B0)
+ UINT8 nfa_dm_rc_workaround[] = { 0x03, 0x0f, 0xab };
+#else
+ UINT8 nfa_dm_rc_workaround[] = { 0x01, 0x0f, 0xab, 0x01 };
+#endif
+
+ ALOGD ("%s: Configure RC work-around", __FUNCTION__);
+ SyncEventGuard guard (sNfaSetConfigEvent);
+ stat = NFA_SetConfig(NCI_PARAM_ID_FW_WORKAROUND, sizeof(nfa_dm_rc_workaround), &nfa_dm_rc_workaround[0]);
+ if (stat == NFA_STATUS_OK)
+ sNfaSetConfigEvent.wait ();
+ }
+
+ // If polling for Active mode, set the ordering so that we choose Active over Passive mode first.
+ if (nat && (nat->tech_mask & (NFA_TECHNOLOGY_MASK_A_ACTIVE | NFA_TECHNOLOGY_MASK_F_ACTIVE)))
+ {
+ UINT8 act_mode_order_param[] = { 0x01 };
+ SyncEventGuard guard (sNfaSetConfigEvent);
+ stat = NFA_SetConfig(NCI_PARAM_ID_ACT_ORDER, sizeof(act_mode_order_param), &act_mode_order_param[0]);
+ if (stat == NFA_STATUS_OK)
+ sNfaSetConfigEvent.wait ();
+ }
+
+ // Set configuration to allow UICC to Power off if there is no traffic.
+ if (GetNumValue(NAME_UICC_IDLE_TIMEOUT, &num, sizeof(num)) && (num != 0))
+ {
+ // 61 => The least significant bit of this byte enables the power off when Idle mode.
+ // 00 87 93 03 == > These 4 bytes form a 4 byte value which decides the idle timeout(in us)
+ // value to trigger the uicc deactivation.
+ // e.g. in current example its value is 0x3938700 i.e. 60000000 is 60 seconds.
+ UINT8 swpcfg_param[] = { 0x61, 0x00, 0x82, 0x04, 0x20, 0xA1, 0x07, 0x00,
+ 0x90, 0xD0, 0x03, 0x00, 0x00, 0x87, 0x93, 0x03 };
+
+ ALOGD ("%s: Configure UICC idle-timeout to %lu ms", __FUNCTION__, num);
+
+ // Set the timeout from the .conf file value.
+ num *= 1000;
+ UINT8 * p = &swpcfg_param[12];
+ UINT32_TO_STREAM(p, num)
+
+ SyncEventGuard guard (sNfaSetConfigEvent);
+ stat = NFA_SetConfig(NCI_PARAM_ID_SWPCFG, sizeof(swpcfg_param), &swpcfg_param[0]);
+ if (stat == NFA_STATUS_OK)
+ sNfaSetConfigEvent.wait ();
+ }
+
+ // Set antenna tuning configuration if configured.
+#define PREINIT_DSP_CFG_SIZE 30
+ UINT8 preinit_dsp_param[PREINIT_DSP_CFG_SIZE];
+
+ if (GetStrValue(NAME_PREINIT_DSP_CFG, (char*)&preinit_dsp_param[0], sizeof(preinit_dsp_param)))
+ {
+ SyncEventGuard guard (sNfaSetConfigEvent);
+ stat = NFA_SetConfig(NCI_PARAM_ID_PREINIT_DSP_CFG, sizeof(preinit_dsp_param), &preinit_dsp_param[0]);
+ if (stat == NFA_STATUS_OK)
+ sNfaSetConfigEvent.wait ();
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: nfcManager_isNfcActive
+**
+** Description: Used externaly to determine if NFC is active or not.
+**
+** Returns: 'true' if the NFC stack is running, else 'false'.
+**
+*******************************************************************************/
+bool nfcManager_isNfcActive()
+{
+ return sIsNfaEnabled;
+}
+
+
+/*******************************************************************************
+**
+** Function: startStopPolling
+**
+** Description: Start or stop polling.
+** isStartPolling: true to start polling; false to stop polling.
+**
+** Returns: None.
+**
+*******************************************************************************/
+void startStopPolling (bool isStartPolling)
+{
+ ALOGD ("%s: enter; isStart=%u", __FUNCTION__, isStartPolling);
+ tNFA_STATUS stat = NFA_STATUS_FAILED;
+
+ startRfDiscovery (false);
+ if (isStartPolling)
+ {
+ tNFA_TECHNOLOGY_MASK tech_mask = DEFAULT_TECH_MASK;
+ unsigned long num = 0;
+ if (GetNumValue(NAME_POLLING_TECH_MASK, &num, sizeof(num)))
+ tech_mask = num;
+
+ SyncEventGuard guard (sNfaEnableDisablePollingEvent);
+ ALOGD ("%s: enable polling", __FUNCTION__);
+ stat = NFA_EnablePolling (tech_mask);
+ if (stat == NFA_STATUS_OK)
+ {
+ ALOGD ("%s: wait for enable event", __FUNCTION__);
+ sNfaEnableDisablePollingEvent.wait (); //wait for NFA_POLL_ENABLED_EVT
+ }
+ else
+ ALOGE ("%s: fail enable polling; error=0x%X", __FUNCTION__, stat);
+ }
+ else
+ {
+ SyncEventGuard guard (sNfaEnableDisablePollingEvent);
+ ALOGD ("%s: disable polling", __FUNCTION__);
+ stat = NFA_DisablePolling ();
+ if (stat == NFA_STATUS_OK)
+ {
+ sNfaEnableDisablePollingEvent.wait (); //wait for NFA_POLL_DISABLED_EVT
+ }
+ else
+ ALOGE ("%s: fail disable polling; error=0x%X", __FUNCTION__, stat);
+ }
+ startRfDiscovery (true);
+ ALOGD ("%s: exit", __FUNCTION__);
+}
+
+
+} /* namespace android */
diff --git a/nci/jni/NativeNfcTag.cpp b/nci/jni/NativeNfcTag.cpp
new file mode 100755
index 0000000..0ba7b21
--- /dev/null
+++ b/nci/jni/NativeNfcTag.cpp
@@ -0,0 +1,1507 @@
+/*
+ * Copyright (C) 2012 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 <errno.h>
+#include <time.h>
+#include <signal.h>
+#include "OverrideLog.h"
+#include "NfcJniUtil.h"
+#include "NfcTag.h"
+#include "config.h"
+#include "Mutex.h"
+#include "IntervalTimer.h"
+#include "JavaClassConstants.h"
+#include "Pn544Interop.h"
+
+extern "C"
+{
+ #include "nfa_api.h"
+ #include "nfa_rw_api.h"
+ #include "ndef_utils.h"
+ #include "rw_api.h"
+}
+namespace android
+{
+ extern nfc_jni_native_data* getNative(JNIEnv *e, jobject o);
+ extern bool nfcManager_isNfcActive();
+ extern int gGeneralTransceiveTimeout;
+}
+
+
+/*****************************************************************************
+**
+** public variables and functions
+**
+*****************************************************************************/
+namespace android
+{
+ bool gIsTagDeactivating = false; // flag for nfa callback indicating we are deactivating for RF interface switch
+ bool gIsSelectingRfInterface = false; // flag for nfa callback indicating we are selecting for RF interface switch
+}
+
+
+/*****************************************************************************
+**
+** private variables and functions
+**
+*****************************************************************************/
+namespace android
+{
+
+
+// Pre-defined tag type values. These must match the values in
+// framework Ndef.java for Google public NFC API.
+#define NDEF_UNKNOWN_TYPE -1
+#define NDEF_TYPE1_TAG 1
+#define NDEF_TYPE2_TAG 2
+#define NDEF_TYPE3_TAG 3
+#define NDEF_TYPE4_TAG 4
+#define NDEF_MIFARE_CLASSIC_TAG 101
+
+#define STATUS_CODE_TARGET_LOST 146 // this error code comes from the service
+
+static uint32_t sCheckNdefCurrentSize = 0;
+static tNFA_STATUS sCheckNdefStatus = 0; //whether tag already contains a NDEF message
+static bool sCheckNdefCapable = false; //whether tag has NDEF capability
+static tNFA_HANDLE sNdefTypeHandlerHandle = NFA_HANDLE_INVALID;
+static tNFA_INTF_TYPE sCurrentRfInterface = NFA_INTERFACE_ISO_DEP;
+static uint8_t* sTransceiveData = NULL;
+static uint32_t sTransceiveDataLen = 0;
+static bool sWaitingForTransceive = false;
+static bool sNeedToSwitchRf = false;
+static Mutex sRfInterfaceMutex;
+static uint32_t sReadDataLen = 0;
+static uint8_t* sReadData = NULL;
+static bool sIsReadingNdefMessage = false;
+static SyncEvent sReadEvent;
+static sem_t sWriteSem;
+static sem_t sFormatSem;
+static SyncEvent sTransceiveEvent;
+static SyncEvent sReconnectEvent;
+static sem_t sCheckNdefSem;
+static sem_t sPresenceCheckSem;
+static sem_t sMakeReadonlySem;
+static IntervalTimer sSwitchBackTimer; // timer used to tell us to switch back to ISO_DEP frame interface
+static jboolean sWriteOk = JNI_FALSE;
+static jboolean sWriteWaitingForComplete = JNI_FALSE;
+static bool sFormatOk = false;
+static jboolean sConnectOk = JNI_FALSE;
+static jboolean sConnectWaitingForComplete = JNI_FALSE;
+static bool sGotDeactivate = false;
+static uint32_t sCheckNdefMaxSize = 0;
+static bool sCheckNdefCardReadOnly = false;
+static jboolean sCheckNdefWaitingForComplete = JNI_FALSE;
+static int sCountTagAway = 0; //count the consecutive number of presence-check failures
+static tNFA_STATUS sMakeReadonlyStatus = NFA_STATUS_FAILED;
+static jboolean sMakeReadonlyWaitingForComplete = JNI_FALSE;
+
+static int reSelect (tNFA_INTF_TYPE rfInterface);
+static bool switchRfInterface(tNFA_INTF_TYPE rfInterface);
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_abortWaits
+**
+** Description: Unblock all thread synchronization objects.
+**
+** Returns: None
+**
+*******************************************************************************/
+void nativeNfcTag_abortWaits ()
+{
+ ALOGD ("%s", __FUNCTION__);
+ {
+ SyncEventGuard g (sReadEvent);
+ sReadEvent.notifyOne ();
+ }
+ sem_post (&sWriteSem);
+ sem_post (&sFormatSem);
+ {
+ SyncEventGuard g (sTransceiveEvent);
+ sTransceiveEvent.notifyOne ();
+ }
+ {
+ SyncEventGuard g (sReconnectEvent);
+ sReconnectEvent.notifyOne ();
+ }
+
+ sem_post (&sCheckNdefSem);
+ sem_post (&sPresenceCheckSem);
+ sem_post (&sMakeReadonlySem);
+}
+
+
+/*******************************************************************************
+**
+** Function: switchBackTimerProc
+**
+** Description: Callback function for interval timer.
+**
+** Returns: None
+**
+*******************************************************************************/
+static void switchBackTimerProc (union sigval)
+{
+ ALOGD ("%s", __FUNCTION__);
+ switchRfInterface(NFA_INTERFACE_ISO_DEP);
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_doReadCompleted
+**
+** Description: Receive the completion status of read operation. Called by
+** NFA_READ_CPLT_EVT.
+** status: Status of operation.
+**
+** Returns: None
+**
+*******************************************************************************/
+void nativeNfcTag_doReadCompleted (tNFA_STATUS status)
+{
+ ALOGD ("%s: status=0x%X; is reading=%u", __FUNCTION__, status, sIsReadingNdefMessage);
+
+ if (sIsReadingNdefMessage == false)
+ return; //not reading NDEF message right now, so just return
+
+ if (status != NFA_STATUS_OK)
+ {
+ sReadDataLen = 0;
+ if (sReadData)
+ free (sReadData);
+ sReadData = NULL;
+ }
+ SyncEventGuard g (sReadEvent);
+ sReadEvent.notifyOne ();
+}
+
+
+/*******************************************************************************
+**
+** Function: ndefHandlerCallback
+**
+** Description: Receive NDEF-message related events from stack.
+** event: Event code.
+** p_data: Event data.
+**
+** Returns: None
+**
+*******************************************************************************/
+static void ndefHandlerCallback (tNFA_NDEF_EVT event, tNFA_NDEF_EVT_DATA *eventData)
+{
+ ALOGD ("%s: event=%u, eventData=%p", __FUNCTION__, event, eventData);
+
+ switch (event)
+ {
+ case NFA_NDEF_REGISTER_EVT:
+ {
+ tNFA_NDEF_REGISTER& ndef_reg = eventData->ndef_reg;
+ ALOGD ("%s: NFA_NDEF_REGISTER_EVT; status=0x%X; h=0x%X", __FUNCTION__, ndef_reg.status, ndef_reg.ndef_type_handle);
+ sNdefTypeHandlerHandle = ndef_reg.ndef_type_handle;
+ }
+ break;
+
+ case NFA_NDEF_DATA_EVT:
+ {
+ ALOGD ("%s: NFA_NDEF_DATA_EVT; data_len = %lu", __FUNCTION__, eventData->ndef_data.len);
+ sReadDataLen = eventData->ndef_data.len;
+ sReadData = (uint8_t*) malloc (sReadDataLen);
+ memcpy (sReadData, eventData->ndef_data.p_data, eventData->ndef_data.len);
+ }
+ break;
+
+ default:
+ ALOGE ("%s: Unknown event %u ????", __FUNCTION__, event);
+ break;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_doRead
+**
+** Description: Read the NDEF message on the tag.
+** e: JVM environment.
+** o: Java object.
+**
+** Returns: NDEF message.
+**
+*******************************************************************************/
+static jbyteArray nativeNfcTag_doRead (JNIEnv *e, jobject o)
+{
+ ALOGD ("%s: enter", __FUNCTION__);
+ tNFA_STATUS status = NFA_STATUS_FAILED;
+ jbyteArray buf = NULL;
+
+ sReadDataLen = 0;
+ if (sReadData != NULL)
+ {
+ free (sReadData);
+ sReadData = NULL;
+ }
+
+ if (sCheckNdefCurrentSize > 0)
+ {
+ {
+ SyncEventGuard g (sReadEvent);
+ sIsReadingNdefMessage = true;
+ status = NFA_RwReadNDef ();
+ sReadEvent.wait (); //wait for NFA_READ_CPLT_EVT
+ }
+ sIsReadingNdefMessage = false;
+
+ if (sReadDataLen > 0) //if stack actually read data from the tag
+ {
+ ALOGD ("%s: read %u bytes", __FUNCTION__, sReadDataLen);
+ buf = e->NewByteArray (sReadDataLen);
+ e->SetByteArrayRegion (buf, 0, sReadDataLen, (jbyte*) sReadData);
+ }
+ }
+ else
+ {
+ ALOGD ("%s: create emtpy buffer", __FUNCTION__);
+ static uint8_t* empty = (uint8_t*) "";
+ sReadDataLen = 0;
+ sReadData = (uint8_t*) malloc (1);
+ buf = e->NewByteArray (sReadDataLen);
+ e->SetByteArrayRegion (buf, 0, sReadDataLen, (jbyte*) sReadData);
+ }
+
+ if (sReadData)
+ {
+ free (sReadData);
+ sReadData = NULL;
+ }
+ sReadDataLen = 0;
+
+ ALOGD ("%s: exit", __FUNCTION__);
+ return buf;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_doWriteStatus
+**
+** Description: Receive the completion status of write operation. Called
+** by NFA_WRITE_CPLT_EVT.
+** isWriteOk: Status of operation.
+**
+** Returns: None
+**
+*******************************************************************************/
+void nativeNfcTag_doWriteStatus (jboolean isWriteOk)
+{
+ if (sWriteWaitingForComplete != JNI_FALSE)
+ {
+ sWriteWaitingForComplete = JNI_FALSE;
+ sWriteOk = isWriteOk;
+ sem_post (&sWriteSem);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_formatStatus
+**
+** Description: Receive the completion status of format operation. Called
+** by NFA_FORMAT_CPLT_EVT.
+** isOk: Status of operation.
+**
+** Returns: None
+**
+*******************************************************************************/
+void nativeNfcTag_formatStatus (bool isOk)
+{
+ sFormatOk = isOk;
+ sem_post (&sFormatSem);
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_doWrite
+**
+** Description: Write a NDEF message to the tag.
+** e: JVM environment.
+** o: Java object.
+** buf: Contains a NDEF message.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+static jboolean nativeNfcTag_doWrite (JNIEnv *e, jobject o, jbyteArray buf)
+{
+ jboolean result = JNI_FALSE;
+ tNFA_STATUS status = 0;
+ UINT32 len = 0;
+ UINT8* p_data = NULL;
+ const int maxBufferSize = 1024;
+ UINT8 buffer[maxBufferSize] = { 0 };
+ UINT32 curDataSize = 0;
+
+ len = (UINT32) e->GetArrayLength (buf);
+ p_data = (UINT8*) e->GetByteArrayElements (buf, NULL);
+
+ ALOGD ("%s: enter; len = %lu", __FUNCTION__, len);
+
+ /* Create the write semaphore */
+ if (sem_init (&sWriteSem, 0, 0) == -1)
+ {
+ ALOGE ("%s: semaphore creation failed (errno=0x%08x)", __FUNCTION__, errno);
+ return JNI_FALSE;
+ }
+
+ sWriteWaitingForComplete = JNI_TRUE;
+ if (sCheckNdefStatus == NFA_STATUS_FAILED)
+ {
+ //if tag does not contain a NDEF message
+ //and tag is capable of storing NDEF message
+ if (sCheckNdefCapable)
+ {
+ ALOGD ("%s: try format", __FUNCTION__);
+ sem_init (&sFormatSem, 0, 0);
+ sFormatOk = false;
+ status = NFA_RwFormatTag ();
+ sem_wait (&sFormatSem);
+ sem_destroy (&sFormatSem);
+ if (sFormatOk == false) //if format operation failed
+ goto TheEnd;
+ }
+ ALOGD ("%s: try write", __FUNCTION__);
+ status = NFA_RwWriteNDef (p_data, len);
+ }
+ else if (len == 0)
+ {
+ //if (NXP TagWriter wants to erase tag) then create and write an empty ndef message
+ NDEF_MsgInit (buffer, maxBufferSize, &curDataSize);
+ status = NDEF_MsgAddRec (buffer, maxBufferSize, &curDataSize, NDEF_TNF_EMPTY, NULL, 0, NULL, 0, NULL, 0);
+ ALOGD ("%s: create empty ndef msg; status=%u; size=%lu", __FUNCTION__, status, curDataSize);
+ status = NFA_RwWriteNDef (buffer, curDataSize);
+ }
+ else
+ {
+ ALOGD ("%s: NFA_RwWriteNDef", __FUNCTION__);
+ status = NFA_RwWriteNDef (p_data, len);
+ }
+
+ if (status != NFA_STATUS_OK)
+ {
+ ALOGE ("%s: write/format error=%d", __FUNCTION__, status);
+ goto TheEnd;
+ }
+
+ /* Wait for write completion status */
+ sWriteOk = false;
+ if (sem_wait (&sWriteSem))
+ {
+ ALOGE ("%s: wait semaphore (errno=0x%08x)", __FUNCTION__, errno);
+ goto TheEnd;
+ }
+
+ result = sWriteOk;
+
+TheEnd:
+ /* Destroy semaphore */
+ if (sem_destroy (&sWriteSem))
+ {
+ ALOGE ("%s: failed destroy semaphore (errno=0x%08x)", __FUNCTION__, errno);
+ }
+ sWriteWaitingForComplete = JNI_FALSE;
+ ALOGD ("%s: exit; result=%d", __FUNCTION__, result);
+ return result;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_doConnectStatus
+**
+** Description: Receive the completion status of connect operation.
+** isConnectOk: Status of the operation.
+**
+** Returns: None
+**
+*******************************************************************************/
+void nativeNfcTag_doConnectStatus (jboolean isConnectOk)
+{
+ if (sConnectWaitingForComplete != JNI_FALSE)
+ {
+ sConnectWaitingForComplete = JNI_FALSE;
+ sConnectOk = isConnectOk;
+ SyncEventGuard g (sReconnectEvent);
+ sReconnectEvent.notifyOne ();
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_doDeactivateStatus
+**
+** Description: Receive the completion status of deactivate operation.
+**
+** Returns: None
+**
+*******************************************************************************/
+void nativeNfcTag_doDeactivateStatus (int status)
+{
+ sGotDeactivate = (status == 0);
+
+ SyncEventGuard g (sReconnectEvent);
+ sReconnectEvent.notifyOne ();
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_doConnect
+**
+** Description: Connect to the tag in RF field.
+** e: JVM environment.
+** o: Java object.
+** targetHandle: Handle of the tag.
+**
+** Returns: Must return NXP status code, which NFC service expects.
+**
+*******************************************************************************/
+static jint nativeNfcTag_doConnect (JNIEnv *e, jobject o, jint targetHandle)
+{
+ ALOGD ("%s: targetHandle = %d", __FUNCTION__, targetHandle);
+ int i = targetHandle;
+ struct nfc_jni_native_data *nat = getNative (0, 0);
+ NfcTag& natTag = NfcTag::getInstance ();
+ int retCode = NFCSTATUS_SUCCESS;
+
+ sNeedToSwitchRf = false;
+ if (i >= NfcTag::MAX_NUM_TECHNOLOGY)
+ {
+ ALOGE ("%s: Handle not found", __FUNCTION__);
+ retCode = NFCSTATUS_FAILED;
+ goto TheEnd;
+ }
+
+ if (natTag.getActivationState() != NfcTag::Active)
+ {
+ ALOGE ("%s: tag already deactivated", __FUNCTION__);
+ retCode = NFCSTATUS_FAILED;
+ goto TheEnd;
+ }
+
+ if (natTag.mTechLibNfcTypes[i] != NFC_PROTOCOL_ISO_DEP)
+ {
+ ALOGD ("%s() Nfc type = %d, do nothing for non ISO_DEP", __FUNCTION__, natTag.mTechLibNfcTypes[i]);
+ retCode = NFCSTATUS_SUCCESS;
+ goto TheEnd;
+ }
+
+ if (natTag.mTechList[i] == TARGET_TYPE_ISO14443_3A || natTag.mTechList[i] == TARGET_TYPE_ISO14443_3B)
+ {
+ ALOGD ("%s: switching to tech: %d need to switch rf intf to frame", __FUNCTION__, natTag.mTechList[i]);
+ // connecting to NfcA or NfcB don't actually switch until/unless we get a transceive
+ sNeedToSwitchRf = true;
+ }
+ else
+ {
+ // connecting back to IsoDep or NDEF
+ return (switchRfInterface (NFA_INTERFACE_ISO_DEP) ? NFCSTATUS_SUCCESS : NFCSTATUS_FAILED);
+ }
+
+TheEnd:
+ ALOGD ("%s: exit 0x%X", __FUNCTION__, retCode);
+ return retCode;
+}
+
+/*******************************************************************************
+**
+** Function: reSelect
+**
+** Description: Deactivates the tag and re-selects it with the specified
+** rf interface.
+**
+** Returns: status code, 0 on success, 1 on failure,
+** 146 (defined in service) on tag lost
+**
+*******************************************************************************/
+static int reSelect (tNFA_INTF_TYPE rfInterface)
+{
+ ALOGD ("%s: enter; rf intf = %d", __FUNCTION__, rfInterface);
+ NfcTag& natTag = NfcTag::getInstance ();
+
+ tNFA_STATUS status;
+ int rVal = 1;
+
+ do
+ {
+ //if tag has shutdown, abort this method
+ if (NfcTag::getInstance ().isNdefDetectionTimedOut())
+ {
+ ALOGD ("%s: ndef detection timeout; break", __FUNCTION__);
+ rVal = STATUS_CODE_TARGET_LOST;
+ break;
+ }
+
+ {
+ SyncEventGuard g (sReconnectEvent);
+ gIsTagDeactivating = true;
+ sGotDeactivate = false;
+ ALOGD ("%s: deactivate to sleep", __FUNCTION__);
+ if (NFA_STATUS_OK != (status = NFA_Deactivate (TRUE))) //deactivate to sleep state
+ {
+ ALOGE ("%s: deactivate failed, status = %d", __FUNCTION__, status);
+ break;
+ }
+
+ if (sReconnectEvent.wait (1000) == false) //if timeout occurred
+ {
+ ALOGE ("%s: timeout waiting for deactivate", __FUNCTION__);
+ }
+ }
+
+ if (NfcTag::getInstance ().getActivationState () != NfcTag::Sleep)
+ {
+ ALOGD ("%s: tag is not in sleep", __FUNCTION__);
+ rVal = STATUS_CODE_TARGET_LOST;
+ break;
+ }
+
+ gIsTagDeactivating = false;
+
+ {
+ SyncEventGuard g2 (sReconnectEvent);
+
+ sConnectWaitingForComplete = JNI_TRUE;
+ ALOGD ("%s: select interface %u", __FUNCTION__, rfInterface);
+ gIsSelectingRfInterface = true;
+ if (NFA_STATUS_OK != (status = NFA_Select (natTag.mTechHandles[0], natTag.mTechLibNfcTypes[0], rfInterface)))
+ {
+ ALOGE ("%s: NFA_Select failed, status = %d", __FUNCTION__, status);
+ break;
+ }
+
+ sConnectOk = false;
+ if (sReconnectEvent.wait (1000) == false) //if timeout occured
+ {
+ ALOGE ("%s: timeout waiting for select", __FUNCTION__);
+ break;
+ }
+ }
+
+ ALOGD("%s: select completed; sConnectOk=%d", __FUNCTION__, sConnectOk);
+ if (NfcTag::getInstance ().getActivationState () != NfcTag::Active)
+ {
+ ALOGD("%s: tag is not active", __FUNCTION__);
+ rVal = STATUS_CODE_TARGET_LOST;
+ break;
+ }
+ rVal = (sConnectOk) ? 0 : 1;
+ } while (0);
+
+ sConnectWaitingForComplete = JNI_FALSE;
+ gIsTagDeactivating = false;
+ gIsSelectingRfInterface = false;
+ ALOGD ("%s: exit; status=%d", __FUNCTION__, rVal);
+ return rVal;
+}
+
+/*******************************************************************************
+**
+** Function: switchRfInterface
+**
+** Description: Switch controller's RF interface to frame, ISO-DEP, or NFC-DEP.
+** rfInterface: Type of RF interface.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+static bool switchRfInterface (tNFA_INTF_TYPE rfInterface)
+{
+ ALOGD ("%s: rf intf = %d", __FUNCTION__, rfInterface);
+ NfcTag& natTag = NfcTag::getInstance ();
+
+ if (natTag.mTechLibNfcTypes[0] != NFC_PROTOCOL_ISO_DEP)
+ {
+ ALOGD ("%s: protocol: %d not ISO_DEP, do nothing", __FUNCTION__, natTag.mTechLibNfcTypes[0]);
+ return true;
+ }
+
+ sRfInterfaceMutex.lock ();
+ ALOGD ("%s: new rf intf = %d, cur rf intf = %d", __FUNCTION__, rfInterface, sCurrentRfInterface);
+
+ bool rVal = true;
+ if (rfInterface != sCurrentRfInterface)
+ {
+ if (rVal = (0 == reSelect(rfInterface)))
+ {
+ sCurrentRfInterface = rfInterface;
+ }
+ }
+
+ sRfInterfaceMutex.unlock ();
+ return rVal;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_doReconnect
+**
+** Description: Re-connect to the tag in RF field.
+** e: JVM environment.
+** o: Java object.
+**
+** Returns: Status code.
+**
+*******************************************************************************/
+static jint nativeNfcTag_doReconnect (JNIEnv *e, jobject o)
+{
+ ALOGD ("%s: enter", __FUNCTION__);
+ int retCode = NFCSTATUS_SUCCESS;
+ NfcTag& natTag = NfcTag::getInstance ();
+
+ if (natTag.getActivationState() != NfcTag::Active)
+ {
+ ALOGE ("%s: tag already deactivated", __FUNCTION__);
+ retCode = NFCSTATUS_FAILED;
+ goto TheEnd;
+ }
+
+ // this is only supported for type 2 or 4 (ISO_DEP) tags
+ if (natTag.mTechLibNfcTypes[0] == NFA_PROTOCOL_ISO_DEP)
+ retCode = reSelect(NFA_INTERFACE_ISO_DEP);
+ else if (natTag.mTechLibNfcTypes[0] == NFA_PROTOCOL_T2T)
+ retCode = reSelect(NFA_INTERFACE_FRAME);
+
+TheEnd:
+ ALOGD ("%s: exit 0x%X", __FUNCTION__, retCode);
+ return retCode;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_doHandleReconnect
+**
+** Description: Re-connect to the tag in RF field.
+** e: JVM environment.
+** o: Java object.
+** targetHandle: Handle of the tag.
+**
+** Returns: Status code.
+**
+*******************************************************************************/
+static jint nativeNfcTag_doHandleReconnect (JNIEnv *e, jobject o, jint targetHandle)
+{
+ ALOGD ("%s: targetHandle = %d", __FUNCTION__, targetHandle);
+ return nativeNfcTag_doConnect (e, o, targetHandle);
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_doDisconnect
+**
+** Description: Deactivate the RF field.
+** e: JVM environment.
+** o: Java object.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+static jboolean nativeNfcTag_doDisconnect (JNIEnv *e, jobject o)
+{
+ ALOGD ("%s: enter", __FUNCTION__);
+ struct nfc_jni_native_data *nat = getNative (0, 0);
+ tNFA_STATUS nfaStat = NFA_STATUS_OK;
+
+ gGeneralTransceiveTimeout = DEFAULT_GENERAL_TRANS_TIMEOUT;
+
+ if (NfcTag::getInstance ().getActivationState () != NfcTag::Active)
+ {
+ ALOGE ("%s: tag already deactivated", __FUNCTION__);
+ goto TheEnd;
+ }
+
+ nfaStat = NFA_Deactivate (FALSE);
+ if (nfaStat != NFA_STATUS_OK)
+ ALOGE ("%s: deactivate failed; error=0x%X", __FUNCTION__, nfaStat);
+
+TheEnd:
+ ALOGD ("%s: exit", __FUNCTION__);
+ return (nfaStat == NFA_STATUS_OK) ? JNI_TRUE : JNI_FALSE;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_doTransceiveStatus
+**
+** Description: Receive the completion status of transceive operation.
+** buf: Contains tag's response.
+** bufLen: Length of buffer.
+**
+** Returns: None
+**
+*******************************************************************************/
+void nativeNfcTag_doTransceiveStatus (uint8_t* buf, uint32_t bufLen)
+{
+ ALOGD ("%s: data len=%d, waiting for transceive: %d", __FUNCTION__, bufLen, sWaitingForTransceive);
+ if (!sWaitingForTransceive)
+ return;
+
+ sTransceiveDataLen = 0;
+ if (bufLen)
+ {
+ if (NULL == (sTransceiveData = (uint8_t *) malloc (bufLen)))
+ {
+ ALOGD ("%s: memory allocation error", __FUNCTION__);
+ }
+ else
+ {
+ memcpy (sTransceiveData, buf, sTransceiveDataLen = bufLen);
+ }
+ }
+
+ {
+ SyncEventGuard g (sTransceiveEvent);
+ sTransceiveEvent.notifyOne ();
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_doTransceive
+**
+** Description: Send raw data to the tag; receive tag's response.
+** e: JVM environment.
+** o: Java object.
+** raw: Not used.
+** statusTargetLost: Whether tag responds or times out.
+**
+** Returns: Response from tag.
+**
+*******************************************************************************/
+static jbyteArray nativeNfcTag_doTransceive (JNIEnv *e, jobject o, jbyteArray data, jboolean raw, jintArray statusTargetLost)
+{
+ ALOGD ("%s: enter; raw=%u; timeout = %d", __FUNCTION__, raw, gGeneralTransceiveTimeout);
+ bool fNeedToSwitchBack = false;
+ nfc_jni_native_data *nat = getNative (0, 0);
+ bool waitOk = false;
+ bool isNack = false;
+ uint8_t *buf = NULL;
+ uint32_t bufLen = 0;
+ jint *targetLost = NULL;
+
+ if (NfcTag::getInstance ().getActivationState () != NfcTag::Active)
+ {
+ if (statusTargetLost)
+ {
+ targetLost = e->GetIntArrayElements (statusTargetLost, 0);
+ if (targetLost)
+ *targetLost = 1; //causes NFC service to throw TagLostException
+ e->ReleaseIntArrayElements (statusTargetLost, targetLost, 0);
+ }
+ ALOGD ("%s: tag not active", __FUNCTION__);
+ return NULL;
+ }
+
+ NfcTag& natTag = NfcTag::getInstance ();
+
+ // get input buffer and length from java call
+ buf = (uint8_t *) e->GetByteArrayElements (data, NULL);
+ bufLen = (uint32_t) e->GetArrayLength (data);
+
+ if (statusTargetLost)
+ {
+ targetLost = e->GetIntArrayElements (statusTargetLost, 0);
+ if (targetLost)
+ *targetLost = 0; //success, tag is still present
+ }
+
+ sSwitchBackTimer.kill ();
+ jbyteArray result = NULL;
+ do
+ {
+ if (sNeedToSwitchRf)
+ {
+ // for ISO_DEP tags connected to NfcA or NfcB we need to be in FRAME interface
+ if (!switchRfInterface (NFA_INTERFACE_FRAME)) //NFA_INTERFACE_ISO_DEP
+ {
+ break;
+ }
+ fNeedToSwitchBack = true;
+ }
+
+ sWaitingForTransceive = true;
+ sTransceiveDataLen = 0;
+ {
+ SyncEventGuard g (sTransceiveEvent);
+ tNFA_STATUS status = NFA_SendRawFrame (buf, bufLen);
+ if (status != NFA_STATUS_OK)
+ {
+ ALOGE ("%s: fail send; error=%d", __FUNCTION__, status);
+ break;
+ }
+ waitOk = sTransceiveEvent.wait (gGeneralTransceiveTimeout);
+ }
+
+ if (waitOk == false) //if timeout occurred
+ {
+ ALOGE ("%s: wait response timeout", __FUNCTION__);
+ if (targetLost)
+ *targetLost = 1; //causes NFC service to throw TagLostException
+ break;
+ }
+
+ if (NfcTag::getInstance ().getActivationState () != NfcTag::Active)
+ {
+ ALOGE ("%s: already deactivated", __FUNCTION__);
+ if (targetLost)
+ *targetLost = 1; //causes NFC service to throw TagLostException
+ break;
+ }
+
+ ALOGD ("%s: response %d bytes", __FUNCTION__, sTransceiveDataLen);
+
+ if ((natTag.getProtocol () == NFA_PROTOCOL_T2T) &&
+ natTag.isT2tNackResponse (sTransceiveData, sTransceiveDataLen))
+ {
+ isNack = true;
+ }
+
+ if (sTransceiveDataLen)
+ {
+ if (!isNack) {
+ // marshall data to java for return
+ result = e->NewByteArray (sTransceiveDataLen);
+ if (result != NULL)
+ {
+ e->SetByteArrayRegion (result, 0, sTransceiveDataLen, (jbyte *) sTransceiveData);
+ }
+ else
+ ALOGE ("%s: Failed to allocate java byte array", __FUNCTION__);
+ } // else a nack is treated as a transceive failure to the upper layers
+
+ free (sTransceiveData);
+ sTransceiveData = NULL;
+ sTransceiveDataLen = 0;
+ }
+ } while (0);
+
+ sWaitingForTransceive = false;
+ e->ReleaseByteArrayElements (data, (jbyte *) buf, JNI_ABORT);
+ if (targetLost)
+ e->ReleaseIntArrayElements (statusTargetLost, targetLost, 0);
+
+ if (fNeedToSwitchBack)
+ {
+ // this timer proc will switch us back to ISO_DEP frame interface
+ sSwitchBackTimer.set (1500, switchBackTimerProc);
+ }
+
+ ALOGD ("%s: exit", __FUNCTION__);
+ return result;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_doGetNdefType
+**
+** Description: Retrieve the type of tag.
+** e: JVM environment.
+** o: Java object.
+** libnfcType: Type of tag represented by JNI.
+** javaType: Not used.
+**
+** Returns: Type of tag represented by NFC Service.
+**
+*******************************************************************************/
+static jint nativeNfcTag_doGetNdefType (JNIEnv *e, jobject o, jint libnfcType, jint javaType)
+{
+ ALOGD ("%s: enter; libnfc type=%d; java type=%d", __FUNCTION__, libnfcType, javaType);
+ jint ndefType = NDEF_UNKNOWN_TYPE;
+
+ // For NFA, libnfcType is mapped to the protocol value received
+ // in the NFA_ACTIVATED_EVT and NFA_DISC_RESULT_EVT event.
+ switch (libnfcType) {
+ case NFA_PROTOCOL_T1T:
+ ndefType = NDEF_TYPE1_TAG;
+ break;
+ case NFA_PROTOCOL_T2T:
+ ndefType = NDEF_TYPE2_TAG;;
+ break;
+ case NFA_PROTOCOL_T3T:
+ ndefType = NDEF_TYPE3_TAG;
+ break;
+ case NFA_PROTOCOL_ISO_DEP:
+ ndefType = NDEF_TYPE4_TAG;
+ break;
+ case NFA_PROTOCOL_ISO15693:
+ ndefType = NDEF_UNKNOWN_TYPE;
+ break;
+ case NFA_PROTOCOL_INVALID:
+ ndefType = NDEF_UNKNOWN_TYPE;
+ break;
+ default:
+ ndefType = NDEF_UNKNOWN_TYPE;
+ break;
+ }
+ ALOGD ("%s: exit; ndef type=%d", __FUNCTION__, ndefType);
+ return ndefType;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_doCheckNdefResult
+**
+** Description: Receive the result of checking whether the tag contains a NDEF
+** message. Called by the NFA_NDEF_DETECT_EVT.
+** status: Status of the operation.
+** maxSize: Maximum size of NDEF message.
+** currentSize: Current size of NDEF message.
+** flags: Indicate various states.
+**
+** Returns: None
+**
+*******************************************************************************/
+void nativeNfcTag_doCheckNdefResult (tNFA_STATUS status, uint32_t maxSize, uint32_t currentSize, uint8_t flags)
+{
+ //this function's flags parameter is defined using the following macros
+ //in nfc/include/rw_api.h;
+ //#define RW_NDEF_FL_READ_ONLY 0x01 /* Tag is read only */
+ //#define RW_NDEF_FL_FORMATED 0x02 /* Tag formated for NDEF */
+ //#define RW_NDEF_FL_SUPPORTED 0x04 /* NDEF supported by the tag */
+ //#define RW_NDEF_FL_UNKNOWN 0x08 /* Unable to find if tag is ndef capable/formated/read only */
+ //#define RW_NDEF_FL_FORMATABLE 0x10 /* Tag supports format operation */
+
+ if (status == NFC_STATUS_BUSY)
+ {
+ ALOGE ("%s: stack is busy", __FUNCTION__);
+ return;
+ }
+
+ if (!sCheckNdefWaitingForComplete)
+ {
+ ALOGE ("%s: not waiting", __FUNCTION__);
+ return;
+ }
+
+ if (flags & RW_NDEF_FL_READ_ONLY)
+ ALOGD ("%s: flag read-only", __FUNCTION__);
+ if (flags & RW_NDEF_FL_FORMATED)
+ ALOGD ("%s: flag formatted for ndef", __FUNCTION__);
+ if (flags & RW_NDEF_FL_SUPPORTED)
+ ALOGD ("%s: flag ndef supported", __FUNCTION__);
+ if (flags & RW_NDEF_FL_UNKNOWN)
+ ALOGD ("%s: flag all unknown", __FUNCTION__);
+ if (flags & RW_NDEF_FL_FORMATABLE)
+ ALOGD ("%s: flag formattable", __FUNCTION__);
+
+ sCheckNdefWaitingForComplete = JNI_FALSE;
+ sCheckNdefStatus = status;
+ sCheckNdefCapable = false; //assume tag is NOT ndef capable
+ if (sCheckNdefStatus == NFA_STATUS_OK)
+ {
+ //NDEF content is on the tag
+ sCheckNdefMaxSize = maxSize;
+ sCheckNdefCurrentSize = currentSize;
+ sCheckNdefCardReadOnly = flags & RW_NDEF_FL_READ_ONLY;
+ sCheckNdefCapable = true;
+ }
+ else if (sCheckNdefStatus == NFA_STATUS_FAILED)
+ {
+ //no NDEF content on the tag
+ sCheckNdefMaxSize = 0;
+ sCheckNdefCurrentSize = 0;
+ sCheckNdefCardReadOnly = flags & RW_NDEF_FL_READ_ONLY;
+ if ((flags & RW_NDEF_FL_UNKNOWN) == 0) //if stack understands the tag
+ {
+ if (flags & RW_NDEF_FL_SUPPORTED) //if tag is ndef capable
+ sCheckNdefCapable = true;
+ }
+ }
+ else
+ {
+ ALOGE ("%s: unknown status=0x%X", __FUNCTION__, status);
+ sCheckNdefMaxSize = 0;
+ sCheckNdefCurrentSize = 0;
+ sCheckNdefCardReadOnly = false;
+ }
+ sem_post (&sCheckNdefSem);
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_doCheckNdef
+**
+** Description: Does the tag contain a NDEF message?
+** e: JVM environment.
+** o: Java object.
+** ndefInfo: NDEF info.
+**
+** Returns: Status code; 0 is success.
+**
+*******************************************************************************/
+static jint nativeNfcTag_doCheckNdef (JNIEnv *e, jobject o, jintArray ndefInfo)
+{
+ tNFA_STATUS status = NFA_STATUS_FAILED;
+ jint* ndef = NULL;
+
+ ALOGD ("%s: enter", __FUNCTION__);
+
+ /* Create the write semaphore */
+ if (sem_init (&sCheckNdefSem, 0, 0) == -1)
+ {
+ ALOGE ("%s: Check NDEF semaphore creation failed (errno=0x%08x)", __FUNCTION__, errno);
+ return JNI_FALSE;
+ }
+
+ if (NfcTag::getInstance ().getActivationState () != NfcTag::Active)
+ {
+ ALOGE ("%s: tag already deactivated", __FUNCTION__);
+ goto TheEnd;
+ }
+
+ ALOGD ("%s: try NFA_RwDetectNDef", __FUNCTION__);
+ sCheckNdefWaitingForComplete = JNI_TRUE;
+ status = NFA_RwDetectNDef ();
+
+ if (status != NFA_STATUS_OK)
+ {
+ ALOGE ("%s: NFA_RwDetectNDef failed, status = 0x%X", __FUNCTION__, status);
+ goto TheEnd;
+ }
+
+ /* Wait for check NDEF completion status */
+ if (sem_wait (&sCheckNdefSem))
+ {
+ ALOGE ("%s: Failed to wait for check NDEF semaphore (errno=0x%08x)", __FUNCTION__, errno);
+ goto TheEnd;
+ }
+
+ if (sCheckNdefStatus == NFA_STATUS_OK)
+ {
+ //stack found a NDEF message on the tag
+ ndef = e->GetIntArrayElements (ndefInfo, 0);
+ if (NfcTag::getInstance ().getProtocol () == NFA_PROTOCOL_T1T)
+ ndef[0] = NfcTag::getInstance ().getT1tMaxMessageSize ();
+ else
+ ndef[0] = sCheckNdefMaxSize;
+ if (sCheckNdefCardReadOnly)
+ ndef[1] = NDEF_MODE_READ_ONLY;
+ else
+ ndef[1] = NDEF_MODE_READ_WRITE;
+ e->ReleaseIntArrayElements (ndefInfo, ndef, 0);
+ status = NFA_STATUS_OK;
+ }
+ else if (sCheckNdefStatus == NFA_STATUS_FAILED)
+ {
+ //stack did not find a NDEF message on the tag;
+ ndef = e->GetIntArrayElements (ndefInfo, 0);
+ if (NfcTag::getInstance ().getProtocol () == NFA_PROTOCOL_T1T)
+ ndef[0] = NfcTag::getInstance ().getT1tMaxMessageSize ();
+ else
+ ndef[0] = sCheckNdefMaxSize;
+ if (sCheckNdefCardReadOnly)
+ ndef[1] = NDEF_MODE_READ_ONLY;
+ else
+ ndef[1] = NDEF_MODE_READ_WRITE;
+ e->ReleaseIntArrayElements (ndefInfo, ndef, 0);
+ status = NFA_STATUS_FAILED;
+ }
+ else if (sCheckNdefStatus == NFA_STATUS_TIMEOUT)
+ {
+ pn544InteropStopPolling ();
+ status = sCheckNdefStatus;
+ }
+ else
+ {
+ ALOGD ("%s: unknown status 0x%X", __FUNCTION__, sCheckNdefStatus);
+ status = sCheckNdefStatus;
+ }
+
+TheEnd:
+ /* Destroy semaphore */
+ if (sem_destroy (&sCheckNdefSem))
+ {
+ ALOGE ("%s: Failed to destroy check NDEF semaphore (errno=0x%08x)", __FUNCTION__, errno);
+ }
+ sCheckNdefWaitingForComplete = JNI_FALSE;
+ ALOGD ("%s: exit; status=0x%X", __FUNCTION__, status);
+ return status;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_resetPresenceCheck
+**
+** Description: Reset variables related to presence-check.
+**
+** Returns: None
+**
+*******************************************************************************/
+void nativeNfcTag_resetPresenceCheck ()
+{
+ sCountTagAway = 0;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_doPresenceCheckResult
+**
+** Description: Receive the result of presence-check.
+** status: Result of presence-check.
+**
+** Returns: None
+**
+*******************************************************************************/
+void nativeNfcTag_doPresenceCheckResult (tNFA_STATUS status)
+{
+ if (status == NFA_STATUS_OK)
+ sCountTagAway = 0;
+ else
+ sCountTagAway++;
+ if (sCountTagAway > 0)
+ ALOGD ("%s: sCountTagAway=%d", __FUNCTION__, sCountTagAway);
+ sem_post (&sPresenceCheckSem);
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_doPresenceCheck
+**
+** Description: Check if the tag is in the RF field.
+** e: JVM environment.
+** o: Java object.
+**
+** Returns: True if tag is in RF field.
+**
+*******************************************************************************/
+static jboolean nativeNfcTag_doPresenceCheck (JNIEnv *e, jobject o)
+{
+ ALOGD ("%s", __FUNCTION__);
+ tNFA_STATUS status = NFA_STATUS_OK;
+ jboolean isPresent = JNI_FALSE;
+
+ if (nfcManager_isNfcActive() == false)
+ {
+ ALOGD ("%s: NFC is no longer active.", __FUNCTION__);
+ return JNI_FALSE;
+ }
+
+ if (NfcTag::getInstance ().getActivationState () != NfcTag::Active)
+ {
+ ALOGD ("%s: tag already deactivated", __FUNCTION__);
+ return JNI_FALSE;
+ }
+
+ if (sem_init (&sPresenceCheckSem, 0, 0) == -1)
+ {
+ ALOGE ("%s: semaphore creation failed (errno=0x%08x)", __FUNCTION__, errno);
+ return JNI_FALSE;
+ }
+
+ status = NFA_RwPresenceCheck ();
+ if (status == NFA_STATUS_OK)
+ {
+ if (sem_wait (&sPresenceCheckSem))
+ {
+ ALOGE ("%s: failed to wait (errno=0x%08x)", __FUNCTION__, errno);
+ }
+ else
+ {
+ isPresent = (sCountTagAway > 3) ? JNI_FALSE : JNI_TRUE;
+ }
+ }
+
+ if (sem_destroy (&sPresenceCheckSem))
+ {
+ ALOGE ("Failed to destroy check NDEF semaphore (errno=0x%08x)", errno);
+ }
+
+ if (isPresent == JNI_FALSE)
+ ALOGD ("%s: tag absent ????", __FUNCTION__);
+ return isPresent;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_doIsNdefFormatable
+**
+** Description: Can tag be formatted to store NDEF message?
+** e: JVM environment.
+** o: Java object.
+** libNfcType: Type of tag.
+** uidBytes: Tag's unique ID.
+** pollBytes: Data from activation.
+** actBytes: Data from activation.
+**
+** Returns: True if formattable.
+**
+*******************************************************************************/
+static jboolean nativeNfcTag_doIsNdefFormatable (JNIEnv *e,
+ jobject o, jint libNfcType, jbyteArray uidBytes, jbyteArray pollBytes,
+ jbyteArray actBytes)
+{
+ jboolean isFormattable = JNI_FALSE;
+
+ switch (NfcTag::getInstance().getProtocol())
+ {
+ case NFA_PROTOCOL_T1T:
+ case NFA_PROTOCOL_ISO15693:
+ isFormattable = JNI_TRUE;
+ break;
+
+ case NFA_PROTOCOL_T2T:
+ isFormattable = NfcTag::getInstance().isMifareUltralight() ? JNI_TRUE : JNI_FALSE;
+ }
+ ALOGD("%s: is formattable=%u", __FUNCTION__, isFormattable);
+ return isFormattable;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_doIsIsoDepNdefFormatable
+**
+** Description: Is ISO-DEP tag formattable?
+** e: JVM environment.
+** o: Java object.
+** pollBytes: Data from activation.
+** actBytes: Data from activation.
+**
+** Returns: True if formattable.
+**
+*******************************************************************************/
+static jboolean nativeNfcTag_doIsIsoDepNdefFormatable (JNIEnv *e, jobject o, jbyteArray pollBytes, jbyteArray actBytes)
+{
+ uint8_t uidFake[] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
+ ALOGD ("%s", __FUNCTION__);
+ jbyteArray uidArray = e->NewByteArray (8);
+ e->SetByteArrayRegion (uidArray, 0, 8, (jbyte*) uidFake);
+ return nativeNfcTag_doIsNdefFormatable (e, o, 0, uidArray, pollBytes, actBytes);
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_doNdefFormat
+**
+** Description: Format a tag so it can store NDEF message.
+** e: JVM environment.
+** o: Java object.
+** key: Not used.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+static jboolean nativeNfcTag_doNdefFormat (JNIEnv *e, jobject o, jbyteArray key)
+{
+ ALOGD ("%s: enter", __FUNCTION__);
+ tNFA_STATUS status = NFA_STATUS_OK;
+
+ sem_init (&sFormatSem, 0, 0);
+ sFormatOk = false;
+ status = NFA_RwFormatTag ();
+ if (status == NFA_STATUS_OK)
+ {
+ ALOGD ("%s: wait for completion", __FUNCTION__);
+ sem_wait (&sFormatSem);
+ status = sFormatOk ? NFA_STATUS_OK : NFA_STATUS_FAILED;
+ }
+ else
+ ALOGE ("%s: error status=%u", __FUNCTION__, status);
+ sem_destroy (&sFormatSem);
+
+ ALOGD ("%s: exit", __FUNCTION__);
+ return (status == NFA_STATUS_OK) ? JNI_TRUE : JNI_FALSE;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_doMakeReadonlyResult
+**
+** Description: Receive the result of making a tag read-only. Called by the
+** NFA_SET_TAG_RO_EVT.
+** status: Status of the operation.
+**
+** Returns: None
+**
+*******************************************************************************/
+void nativeNfcTag_doMakeReadonlyResult (tNFA_STATUS status)
+{
+ if (sMakeReadonlyWaitingForComplete != JNI_FALSE)
+ {
+ sMakeReadonlyWaitingForComplete = JNI_FALSE;
+ sMakeReadonlyStatus = status;
+
+ sem_post (&sMakeReadonlySem);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_doMakeReadonly
+**
+** Description: Make the tag read-only.
+** e: JVM environment.
+** o: Java object.
+** key: Key to access the tag.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+static jboolean nativeNfcTag_doMakeReadonly (JNIEnv *e, jobject o, jbyteArray key)
+{
+ jboolean result = JNI_FALSE;
+ tNFA_STATUS status;
+
+ ALOGD ("%s", __FUNCTION__);
+
+ /* Create the make_readonly semaphore */
+ if (sem_init (&sMakeReadonlySem, 0, 0) == -1)
+ {
+ ALOGE ("%s: Make readonly semaphore creation failed (errno=0x%08x)", __FUNCTION__, errno);
+ return JNI_FALSE;
+ }
+
+ sMakeReadonlyWaitingForComplete = JNI_TRUE;
+
+ // Hard-lock the tag (cannot be reverted)
+ status = NFA_RwSetTagReadOnly(TRUE);
+
+ if (status != NFA_STATUS_OK)
+ {
+ ALOGE ("%s: NFA_RwSetTagReadOnly failed, status = %d", __FUNCTION__, status);
+ goto TheEnd;
+ }
+
+ /* Wait for check NDEF completion status */
+ if (sem_wait (&sMakeReadonlySem))
+ {
+ ALOGE ("%s: Failed to wait for make_readonly semaphore (errno=0x%08x)", __FUNCTION__, errno);
+ goto TheEnd;
+ }
+
+ if (sMakeReadonlyStatus == NFA_STATUS_OK)
+ {
+ result = JNI_TRUE;
+ }
+
+TheEnd:
+ /* Destroy semaphore */
+ if (sem_destroy (&sMakeReadonlySem))
+ {
+ ALOGE ("%s: Failed to destroy read_only semaphore (errno=0x%08x)", __FUNCTION__, errno);
+ }
+ sMakeReadonlyWaitingForComplete = JNI_FALSE;
+ return result;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_registerNdefTypeHandler
+**
+** Description: Register a callback to receive NDEF message from the tag
+** from the NFA_NDEF_DATA_EVT.
+**
+** Returns: None
+**
+*******************************************************************************/
+//register a callback to receive NDEF message from the tag
+//from the NFA_NDEF_DATA_EVT;
+void nativeNfcTag_registerNdefTypeHandler ()
+{
+ ALOGD ("%s", __FUNCTION__);
+ sNdefTypeHandlerHandle = NFA_HANDLE_INVALID;
+ NFA_RegisterNDefTypeHandler (TRUE, NFA_TNF_DEFAULT, (UINT8 *) "", 0, ndefHandlerCallback);
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_deregisterNdefTypeHandler
+**
+** Description: No longer need to receive NDEF message from the tag.
+**
+** Returns: None
+**
+*******************************************************************************/
+void nativeNfcTag_deregisterNdefTypeHandler ()
+{
+ ALOGD ("%s", __FUNCTION__);
+ NFA_DeregisterNDefTypeHandler (sNdefTypeHandlerHandle);
+ sNdefTypeHandlerHandle = NFA_HANDLE_INVALID;
+}
+
+
+/*****************************************************************************
+**
+** JNI functions for Android 4.0.3
+**
+*****************************************************************************/
+static JNINativeMethod gMethods[] =
+{
+ {"doConnect", "(I)I", (void *)nativeNfcTag_doConnect},
+ {"doDisconnect", "()Z", (void *)nativeNfcTag_doDisconnect},
+ {"doReconnect", "()I", (void *)nativeNfcTag_doReconnect},
+ {"doHandleReconnect", "(I)I", (void *)nativeNfcTag_doHandleReconnect},
+ {"doTransceive", "([BZ[I)[B", (void *)nativeNfcTag_doTransceive},
+ {"doGetNdefType", "(II)I", (void *)nativeNfcTag_doGetNdefType},
+ {"doCheckNdef", "([I)I", (void *)nativeNfcTag_doCheckNdef},
+ {"doRead", "()[B", (void *)nativeNfcTag_doRead},
+ {"doWrite", "([B)Z", (void *)nativeNfcTag_doWrite},
+ {"doPresenceCheck", "()Z", (void *)nativeNfcTag_doPresenceCheck},
+ {"doIsIsoDepNdefFormatable", "([B[B)Z", (void *)nativeNfcTag_doIsIsoDepNdefFormatable},
+ {"doNdefFormat", "([B)Z", (void *)nativeNfcTag_doNdefFormat},
+ {"doMakeReadonly", "([B)Z", (void *)nativeNfcTag_doMakeReadonly},
+};
+
+
+/*******************************************************************************
+**
+** Function: register_com_android_nfc_NativeNfcTag
+**
+** Description: Regisgter JNI functions with Java Virtual Machine.
+** e: Environment of JVM.
+**
+** Returns: Status of registration.
+**
+*******************************************************************************/
+int register_com_android_nfc_NativeNfcTag (JNIEnv *e)
+{
+ ALOGD ("%s", __FUNCTION__);
+ return jniRegisterNativeMethods (e, gNativeNfcTagClassName, gMethods, NELEM (gMethods));
+}
+
+
+} /* namespace android */
diff --git a/nci/jni/NativeP2pDevice.cpp b/nci/jni/NativeP2pDevice.cpp
new file mode 100644
index 0000000..57f9dad
--- /dev/null
+++ b/nci/jni/NativeP2pDevice.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2012 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 "OverrideLog.h"
+#include "NfcJniUtil.h"
+#include "JavaClassConstants.h"
+
+
+namespace android
+{
+
+
+static jboolean nativeP2pDeviceDoConnect (JNIEnv* e, jobject o)
+{
+ ALOGD ("%s", __FUNCTION__);
+ return JNI_TRUE;
+}
+
+
+static jboolean nativeP2pDeviceDoDisconnect (JNIEnv* e, jobject o)
+{
+ ALOGD ("%s", __FUNCTION__);
+ return JNI_TRUE;
+}
+
+
+static jbyteArray nativeP2pDeviceDoTransceive (JNIEnv* e, jobject o, jbyteArray data)
+{
+ ALOGD ("%s", __FUNCTION__);
+ return NULL;
+}
+
+
+static jbyteArray nativeP2pDeviceDoReceive (JNIEnv* e, jobject o)
+{
+ ALOGD ("%s", __FUNCTION__);
+ return NULL;
+}
+
+
+static jboolean nativeP2pDeviceDoSend (JNIEnv* e, jobject o, jbyteArray buf)
+{
+ ALOGD ("%s", __FUNCTION__);
+ return JNI_TRUE;
+}
+
+
+/*****************************************************************************
+**
+** Description: JNI functions
+**
+*****************************************************************************/
+static JNINativeMethod gMethods[] =
+{
+ {"doConnect", "()Z", (void *) nativeP2pDeviceDoConnect},
+ {"doDisconnect", "()Z", (void *) nativeP2pDeviceDoDisconnect},
+ {"doTransceive", "([B)[B", (void *) nativeP2pDeviceDoTransceive},
+ {"doReceive", "()[B", (void *) nativeP2pDeviceDoReceive},
+ {"doSend", "([B)Z", (void *) nativeP2pDeviceDoSend},
+};
+
+
+/*******************************************************************************
+**
+** Function: register_com_android_nfc_NativeP2pDevice
+**
+** Description: Regisgter JNI functions with Java Virtual Machine.
+** e: Environment of JVM.
+**
+** Returns: Status of registration.
+**
+*******************************************************************************/
+int register_com_android_nfc_NativeP2pDevice (JNIEnv* e)
+{
+ return jniRegisterNativeMethods (e, gNativeP2pDeviceClassName,
+ gMethods, NELEM(gMethods));
+}
+
+
+} // namepspace android
diff --git a/nci/jni/NativeSecureElement.cpp b/nci/jni/NativeSecureElement.cpp
new file mode 100755
index 0000000..1a2a73a
--- /dev/null
+++ b/nci/jni/NativeSecureElement.cpp
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2012 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 "OverrideLog.h"
+#include "SecureElement.h"
+#include "JavaClassConstants.h"
+#include "PowerSwitch.h"
+
+
+namespace android
+{
+
+
+extern void com_android_nfc_NfcManager_disableDiscovery (JNIEnv* e, jobject o);
+extern void com_android_nfc_NfcManager_enableDiscovery (JNIEnv* e, jobject o, jint mode);
+extern int gGeneralTransceiveTimeout;
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcSecureElement_doOpenSecureElementConnection
+**
+** Description: Connect to the secure element.
+** e: JVM environment.
+** o: Java object.
+**
+** Returns: Handle of secure element. 0 is failure.
+**
+*******************************************************************************/
+static jint nativeNfcSecureElement_doOpenSecureElementConnection (JNIEnv* e, jobject o)
+{
+ ALOGD("%s: enter", __FUNCTION__);
+ bool stat = true;
+ jint secElemHandle = 0;
+ SecureElement &se = SecureElement::getInstance();
+
+ if (se.isActivatedInListenMode()) {
+ ALOGD("Denying SE open due to SE listen mode active");
+ goto TheEnd;
+ }
+
+ if (se.isRfFieldOn()) {
+ ALOGD("Denying SE open due to SE in active RF field");
+ goto TheEnd;
+ }
+ //tell the controller to power up to get ready for sec elem operations
+ PowerSwitch::getInstance ().setLevel (PowerSwitch::FULL_POWER);
+ PowerSwitch::getInstance ().setModeOn (PowerSwitch::SE_CONNECTED);
+
+ //if controller is not routing AND there is no pipe connected,
+ //then turn on the sec elem
+ if (! se.isBusy())
+ stat = se.activate(0);
+
+ if (stat)
+ {
+ //establish a pipe to sec elem
+ stat = se.connectEE();
+ if (stat)
+ secElemHandle = se.mActiveEeHandle;
+ else
+ se.deactivate (0);
+ }
+
+ //if code fails to connect to the secure element, and nothing is active, then
+ //tell the controller to power down
+ if ((!stat) && (! PowerSwitch::getInstance ().setModeOff (PowerSwitch::SE_CONNECTED)))
+ {
+ PowerSwitch::getInstance ().setLevel (PowerSwitch::LOW_POWER);
+ }
+
+TheEnd:
+ ALOGD("%s: exit; return handle=0x%X", __FUNCTION__, secElemHandle);
+ return secElemHandle;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcSecureElement_doDisconnectSecureElementConnection
+**
+** Description: Disconnect from the secure element.
+** e: JVM environment.
+** o: Java object.
+** handle: Handle of secure element.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+static jboolean nativeNfcSecureElement_doDisconnectSecureElementConnection (JNIEnv* e, jobject o, jint handle)
+{
+ ALOGD("%s: enter; handle=0x%04x", __FUNCTION__, handle);
+ bool stat = false;
+
+ stat = SecureElement::getInstance().disconnectEE (handle);
+
+ //if controller is not routing AND there is no pipe connected,
+ //then turn off the sec elem
+ if (! SecureElement::getInstance().isBusy())
+ SecureElement::getInstance().deactivate (handle);
+
+ //if nothing is active after this, then tell the controller to power down
+ if (! PowerSwitch::getInstance ().setModeOff (PowerSwitch::SE_CONNECTED))
+ PowerSwitch::getInstance ().setLevel (PowerSwitch::LOW_POWER);
+
+ ALOGD("%s: exit", __FUNCTION__);
+ return stat ? JNI_TRUE : JNI_FALSE;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcSecureElement_doTransceive
+**
+** Description: Send data to the secure element; retrieve response.
+** e: JVM environment.
+** o: Java object.
+** handle: Secure element's handle.
+** data: Data to send.
+**
+** Returns: Buffer of received data.
+**
+*******************************************************************************/
+static jbyteArray nativeNfcSecureElement_doTransceive (JNIEnv* e, jobject o, jint handle, jbyteArray data)
+{
+ UINT8* buf = NULL;
+ INT32 buflen = 0;
+ const INT32 recvBufferMaxSize = 1024;
+ UINT8 recvBuffer [recvBufferMaxSize];
+ INT32 recvBufferActualSize = 0;
+ jbyteArray result = NULL;
+
+ buf = (UINT8*) e->GetByteArrayElements (data, NULL);
+ buflen = e->GetArrayLength (data);
+
+ ALOGD("%s: enter; handle=0x%X; buf len=%ld", __FUNCTION__, handle, buflen);
+ SecureElement::getInstance().transceive (buf, buflen, recvBuffer, recvBufferMaxSize, recvBufferActualSize, gGeneralTransceiveTimeout);
+
+ //copy results back to java
+ result = e->NewByteArray (recvBufferActualSize);
+ if (result != NULL)
+ {
+ e->SetByteArrayRegion (result, 0, recvBufferActualSize, (jbyte *) recvBuffer);
+ }
+
+ e->ReleaseByteArrayElements (data, (jbyte *) buf, JNI_ABORT);
+ ALOGD("%s: exit: recv len=%ld", __FUNCTION__, recvBufferActualSize);
+ return result;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcSecureElement_doGetUid
+**
+** Description: Get the secure element's unique ID.
+** e: JVM environment.
+** o: Java object.
+** handle: Handle of secure element.
+**
+** Returns: Secure element's unique ID.
+**
+*******************************************************************************/
+static jbyteArray nativeNfcSecureElement_doGetUid (JNIEnv* e, jobject o, jint handle)
+{
+ ALOGD("%s: enter; handle=0x%X", __FUNCTION__, handle);
+ jbyteArray secureElementUid = NULL;
+
+ SecureElement::getInstance ().getUiccId (handle, secureElementUid);
+
+ ALOGD("%s: exit", __FUNCTION__);
+ return secureElementUid;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcSecureElement_doGetTechList
+**
+** Description: Get a list of technologies that the secure element supports.
+** e: JVM environment.
+** o: Java object.
+** handle: Handle of secure element.
+**
+** Returns: Array of technologies.
+**
+*******************************************************************************/
+static jintArray nativeNfcSecureElement_doGetTechList (JNIEnv* e, jobject o, jint handle)
+{
+ ALOGD("%s: enter; handle=0x%X", __FUNCTION__, handle);
+ jintArray techList = NULL;
+
+ SecureElement::getInstance().getTechnologyList (handle, techList);
+
+ ALOGD("%s: exit", __FUNCTION__);
+ return techList;
+}
+
+
+/*****************************************************************************
+**
+** Description: JNI functions
+**
+*****************************************************************************/
+static JNINativeMethod gMethods[] =
+{
+ {"doNativeOpenSecureElementConnection", "()I", (void *) nativeNfcSecureElement_doOpenSecureElementConnection},
+ {"doNativeDisconnectSecureElementConnection", "(I)Z", (void *) nativeNfcSecureElement_doDisconnectSecureElementConnection},
+ {"doTransceive", "(I[B)[B", (void *) nativeNfcSecureElement_doTransceive},
+ {"doGetUid", "(I)[B", (void *) nativeNfcSecureElement_doGetUid},
+ {"doGetTechList", "(I)[I", (void *) nativeNfcSecureElement_doGetTechList},
+};
+
+
+/*******************************************************************************
+**
+** Function: register_com_android_nfc_NativeNfcSecureElement
+**
+** Description: Regisgter JNI functions with Java Virtual Machine.
+** e: Environment of JVM.
+**
+** Returns: Status of registration.
+**
+*******************************************************************************/
+int register_com_android_nfc_NativeNfcSecureElement(JNIEnv *e)
+{
+ return jniRegisterNativeMethods(e, gNativeNfcSecureElementClassName,
+ gMethods, NELEM(gMethods));
+}
+
+
+} // namespace android
+
diff --git a/nci/jni/NfcJniUtil.cpp b/nci/jni/NfcJniUtil.cpp
new file mode 100755
index 0000000..9921cae
--- /dev/null
+++ b/nci/jni/NfcJniUtil.cpp
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2012 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 "NfcJniUtil.h"
+#include <errno.h>
+
+
+/*******************************************************************************
+**
+** Function: JNI_OnLoad
+**
+** Description: Register all JNI functions with Java Virtual Machine.
+** jvm: Java Virtual Machine.
+** reserved: Not used.
+**
+** Returns: JNI version.
+**
+*******************************************************************************/
+jint JNI_OnLoad (JavaVM *jvm, void *reserved)
+{
+ ALOGD ("%s: enter", __FUNCTION__);
+ JNIEnv *e = NULL;
+
+ // 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_NativeLlcpServiceSocket (e) == -1)
+ return JNI_ERR;
+ if (android::register_com_android_nfc_NativeLlcpSocket (e) == -1)
+ return JNI_ERR;
+ if (android::register_com_android_nfc_NativeNfcTag (e) == -1)
+ return JNI_ERR;
+ if (android::register_com_android_nfc_NativeLlcpConnectionlessSocket (e) == -1)
+ return JNI_ERR;
+ if (android::register_com_android_nfc_NativeP2pDevice (e) == -1)
+ return JNI_ERR;
+ if (android::register_com_android_nfc_NativeNfcSecureElement (e) == -1)
+ return JNI_ERR;
+ ALOGD ("%s: exit", __FUNCTION__);
+ return JNI_VERSION_1_6;
+}
+
+
+namespace android
+{
+
+
+/*******************************************************************************
+**
+** Function: nfc_jni_cache_object
+**
+** Description:
+**
+** Returns: Status code.
+**
+*******************************************************************************/
+int nfc_jni_cache_object (JNIEnv *e, const char *className, jobject *cachedObj)
+{
+ jclass cls = NULL;
+ jobject obj = NULL;
+ jmethodID ctor = 0;
+
+ cls = e->FindClass (className);
+ if(cls == NULL)
+ {
+ ALOGE ("%s: find class error", __FUNCTION__);
+ return -1;
+ }
+
+ ctor = e->GetMethodID (cls, "<init>", "()V");
+ obj = e->NewObject (cls, ctor);
+ if (obj == NULL)
+ {
+ ALOGE ("%s: create object error", __FUNCTION__);
+ return -1;
+ }
+
+ *cachedObj = e->NewGlobalRef (obj);
+ if (*cachedObj == NULL)
+ {
+ e->DeleteLocalRef (obj);
+ ALOGE ("%s: global ref error", __FUNCTION__);
+ return -1;
+ }
+ e->DeleteLocalRef (obj);
+ return 0;
+}
+
+
+/*******************************************************************************
+**
+** Function: nfc_jni_get_nfc_socket_handle
+**
+** Description: Get the value of "mHandle" member variable.
+** e: JVM environment.
+** o: Java object.
+**
+** Returns: Value of mHandle.
+**
+*******************************************************************************/
+int nfc_jni_get_nfc_socket_handle (JNIEnv *e, jobject o)
+{
+ jclass c = NULL;
+ jfieldID f = 0;
+
+ c = e->GetObjectClass (o);
+ f = e->GetFieldID (c, "mHandle", "I");
+ return e->GetIntField (o, f);
+}
+
+
+/*******************************************************************************
+**
+** Function: nfc_jni_get_nat
+**
+** Description: Get the value of "mNative" member variable.
+** e: JVM environment.
+** o: Java object.
+**
+** Returns: Pointer to the value of mNative.
+**
+*******************************************************************************/
+struct nfc_jni_native_data* nfc_jni_get_nat(JNIEnv *e, jobject o)
+{
+ jclass c = NULL;
+ jfieldID f = 0;
+
+ /* Retrieve native structure address */
+ c = e->GetObjectClass(o);
+ f = e->GetFieldID(c, "mNative", "I");
+ return (struct nfc_jni_native_data*)e->GetIntField(o, f);
+}
+
+
+} // namespace android
diff --git a/nci/jni/NfcJniUtil.h b/nci/jni/NfcJniUtil.h
new file mode 100755
index 0000000..8caa0b8
--- /dev/null
+++ b/nci/jni/NfcJniUtil.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#pragma once
+#define LOG_TAG "BrcmNfcJni"
+#include <JNIHelp.h>
+#include <jni.h>
+#include <pthread.h>
+#include <sys/queue.h>
+#include <semaphore.h>
+
+
+/* Discovery modes -- keep in sync with NFCManager.DISCOVERY_MODE_* */
+#define DISCOVERY_MODE_TAG_READER 0
+#define DISCOVERY_MODE_NFCIP1 1
+#define DISCOVERY_MODE_CARD_EMULATION 2
+#define DISCOVERY_MODE_TABLE_SIZE 3
+
+#define DISCOVERY_MODE_DISABLED 0
+#define DISCOVERY_MODE_ENABLED 1
+
+#define MODE_P2P_TARGET 0
+#define MODE_P2P_INITIATOR 1
+
+
+/* Properties values */
+#define PROPERTY_LLCP_LTO 0
+#define PROPERTY_LLCP_MIU 1
+#define PROPERTY_LLCP_WKS 2
+#define PROPERTY_LLCP_OPT 3
+#define PROPERTY_NFC_DISCOVERY_A 4
+#define PROPERTY_NFC_DISCOVERY_B 5
+#define PROPERTY_NFC_DISCOVERY_F 6
+#define PROPERTY_NFC_DISCOVERY_15693 7
+#define PROPERTY_NFC_DISCOVERY_NCFIP 8
+
+
+/* Error codes */
+#define ERROR_BUFFER_TOO_SMALL -12
+#define ERROR_INSUFFICIENT_RESOURCES -9
+
+
+/* Pre-defined tag type values. These must match the values in
+ * Ndef.java in the framework.
+ */
+#define NDEF_UNKNOWN_TYPE -1
+#define NDEF_TYPE1_TAG 1
+#define NDEF_TYPE2_TAG 2
+#define NDEF_TYPE3_TAG 3
+#define NDEF_TYPE4_TAG 4
+#define NDEF_MIFARE_CLASSIC_TAG 101
+
+
+/* Pre-defined card read/write state values. These must match the values in
+ * Ndef.java in the framework.
+ */
+#define NDEF_MODE_READ_ONLY 1
+#define NDEF_MODE_READ_WRITE 2
+#define NDEF_MODE_UNKNOWN 3
+
+
+/* Name strings for target types. These *must* match the values in TagTechnology.java */
+#define TARGET_TYPE_UNKNOWN -1
+#define TARGET_TYPE_ISO14443_3A 1
+#define TARGET_TYPE_ISO14443_3B 2
+#define TARGET_TYPE_ISO14443_4 3
+#define TARGET_TYPE_FELICA 4
+#define TARGET_TYPE_ISO15693 5
+#define TARGET_TYPE_NDEF 6
+#define TARGET_TYPE_NDEF_FORMATABLE 7
+#define TARGET_TYPE_MIFARE_CLASSIC 8
+#define TARGET_TYPE_MIFARE_UL 9
+
+
+//define a few NXP error codes that NFC service expects;
+//see external/libnfc-nxp/src/phLibNfcStatus.h;
+//see external/libnfc-nxp/inc/phNfcStatus.h
+#define NFCSTATUS_SUCCESS (0x0000)
+#define NFCSTATUS_FAILED (0x00FF)
+
+//default general trasceive timeout in millisecond
+#define DEFAULT_GENERAL_TRANS_TIMEOUT 1000
+
+struct nfc_jni_native_data
+{
+ /* Thread handle */
+ pthread_t thread;
+ int running;
+
+ /* Our VM */
+ JavaVM *vm;
+ int env_version;
+
+ /* Reference to the NFCManager instance */
+ jobject manager;
+
+ /* Cached objects */
+ jobject cached_NfcTag;
+ jobject cached_P2pDevice;
+
+ /* Secure Element selected */
+ int seId;
+
+ /* LLCP params */
+ int lto;
+ int miu;
+ int wks;
+ int opt;
+
+ int tech_mask;
+
+ /* Tag detected */
+ jobject tag;
+
+ int tHandle;
+ int tProtocols[16];
+ int handles[16];
+};
+
+
+extern "C"
+{
+ jint JNI_OnLoad(JavaVM *jvm, void *reserved);
+}
+
+
+namespace android
+{
+ int nfc_jni_cache_object (JNIEnv *e, const char *clsname, jobject *cached_obj);
+ int nfc_jni_get_nfc_socket_handle (JNIEnv *e, jobject o);
+ struct nfc_jni_native_data* nfc_jni_get_nat (JNIEnv *e, jobject o);
+ int register_com_android_nfc_NativeNfcManager (JNIEnv *e);
+ int register_com_android_nfc_NativeNfcTag (JNIEnv *e);
+ int register_com_android_nfc_NativeP2pDevice (JNIEnv *e);
+ 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/nci/jni/NfcTag.cpp b/nci/jni/NfcTag.cpp
new file mode 100755
index 0000000..b94355f
--- /dev/null
+++ b/nci/jni/NfcTag.cpp
@@ -0,0 +1,1325 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+/*
+ * Tag-reading, tag-writing operations.
+ */
+#include "OverrideLog.h"
+#include "NfcTag.h"
+#include "JavaClassConstants.h"
+extern "C"
+{
+ #include "rw_int.h"
+}
+
+
+/*******************************************************************************
+**
+** Function: NfcTag
+**
+** Description: Initialize member variables.
+**
+** Returns: None
+**
+*******************************************************************************/
+NfcTag::NfcTag ()
+: mNativeData (NULL),
+ mActivationState (Idle),
+ mProtocol(NFC_PROTOCOL_UNKNOWN),
+ mNumTechList (0),
+ mtT1tMaxMessageSize (0),
+ mReadCompletedStatus (NFA_STATUS_OK),
+ mLastKovioUidLen (0),
+ mNdefDetectionTimedOut (false)
+{
+ memset (mTechList, 0, sizeof(mTechList));
+ memset (mTechHandles, 0, sizeof(mTechHandles));
+ memset (mTechLibNfcTypes, 0, sizeof(mTechLibNfcTypes));
+ memset (mTechParams, 0, sizeof(mTechParams));
+ memset(mLastKovioUid, 0, NFC_KOVIO_MAX_LEN);
+}
+
+
+/*******************************************************************************
+**
+** Function: getInstance
+**
+** Description: Get a reference to the singleton NfcTag object.
+**
+** Returns: Reference to NfcTag object.
+**
+*******************************************************************************/
+NfcTag& NfcTag::getInstance ()
+{
+ static NfcTag tag;
+ return tag;
+}
+
+
+/*******************************************************************************
+**
+** Function: initialize
+**
+** Description: Reset member variables.
+** native: Native data.
+**
+** Returns: None
+**
+*******************************************************************************/
+void NfcTag::initialize (nfc_jni_native_data* native)
+{
+ mNativeData = native;
+ mActivationState = Idle;
+ mProtocol = NFC_PROTOCOL_UNKNOWN;
+ mNumTechList = 0;
+ mtT1tMaxMessageSize = 0;
+ mReadCompletedStatus = NFA_STATUS_OK;
+ resetTechnologies ();
+}
+
+
+/*******************************************************************************
+**
+** Function: abort
+**
+** Description: Unblock all operations.
+**
+** Returns: None
+**
+*******************************************************************************/
+void NfcTag::abort ()
+{
+ SyncEventGuard g (mReadCompleteEvent);
+ mReadCompleteEvent.notifyOne ();
+}
+
+
+/*******************************************************************************
+**
+** Function: getActivationState
+**
+** Description: What is the current state: Idle, Sleep, or Activated.
+**
+** Returns: Idle, Sleep, or Activated.
+**
+*******************************************************************************/
+NfcTag::ActivationState NfcTag::getActivationState ()
+{
+ return mActivationState;
+}
+
+
+/*******************************************************************************
+**
+** Function: setDeactivationState
+**
+** Description: Set the current state: Idle or Sleep.
+** deactivated: state of deactivation.
+**
+** Returns: None.
+**
+*******************************************************************************/
+void NfcTag::setDeactivationState (tNFA_DEACTIVATED& deactivated)
+{
+ static const char fn [] = "NfcTag::setDeactivationState";
+ mActivationState = Idle;
+ mNdefDetectionTimedOut = false;
+ if (deactivated.type == NFA_DEACTIVATE_TYPE_SLEEP)
+ mActivationState = Sleep;
+ ALOGD ("%s: state=%u", fn, mActivationState);
+}
+
+
+/*******************************************************************************
+**
+** Function: setActivationState
+**
+** Description: Set the current state to Active.
+**
+** Returns: None.
+**
+*******************************************************************************/
+void NfcTag::setActivationState ()
+{
+ static const char fn [] = "NfcTag::setActivationState";
+ mNdefDetectionTimedOut = false;
+ mActivationState = Active;
+ ALOGD ("%s: state=%u", fn, mActivationState);
+}
+
+
+/*******************************************************************************
+**
+** Function: getProtocol
+**
+** Description: Get the protocol of the current tag.
+**
+** Returns: Protocol number.
+**
+*******************************************************************************/
+tNFC_PROTOCOL NfcTag::getProtocol()
+{
+ return mProtocol;
+}
+
+/*******************************************************************************
+**
+** Function TimeDiff
+**
+** Description Computes time difference in milliseconds.
+**
+** Returns Time difference in milliseconds
+**
+*******************************************************************************/
+UINT32 TimeDiff(timespec start, timespec end)
+{
+ timespec temp;
+ if ((end.tv_nsec-start.tv_nsec)<0)
+ {
+ temp.tv_sec = end.tv_sec-start.tv_sec-1;
+ temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec;
+ }
+ else
+ {
+ temp.tv_sec = end.tv_sec-start.tv_sec;
+ temp.tv_nsec = end.tv_nsec-start.tv_nsec;
+ }
+
+ return (temp.tv_sec * 1000) + (temp.tv_nsec / 1000000);
+}
+
+/*******************************************************************************
+**
+** Function: IsSameKovio
+**
+** Description: Checks if tag activate is the same (UID) Kovio tag previously
+** activated. This is needed due to a problem with some Kovio
+** tags re-activating multiple times.
+** activationData: data from activation.
+**
+** Returns: true if the activation is from the same tag previously
+** activated, false otherwise
+**
+*******************************************************************************/
+bool NfcTag::IsSameKovio(tNFA_ACTIVATED& activationData)
+{
+ static const char fn [] = "NfcTag::IsSameKovio";
+ ALOGD ("%s: enter", fn);
+ tNFC_ACTIVATE_DEVT& rfDetail = activationData.activate_ntf;
+
+ if (rfDetail.protocol != NFC_PROTOCOL_KOVIO)
+ return false;
+
+ memcpy (&(mTechParams[0]), &(rfDetail.rf_tech_param), sizeof(rfDetail.rf_tech_param));
+ if (mTechParams [0].mode != NFC_DISCOVERY_TYPE_POLL_KOVIO)
+ return false;
+
+ struct timespec now;
+ clock_gettime(CLOCK_REALTIME, &now);
+
+ bool rVal = false;
+ if (mTechParams[0].param.pk.uid_len == mLastKovioUidLen)
+ {
+ if (memcmp(mLastKovioUid, &mTechParams [0].param.pk.uid, mTechParams[0].param.pk.uid_len) == 0)
+ {
+ //same tag
+ if (TimeDiff(mLastKovioTime, now) < 500)
+ {
+ // same tag within 500 ms, ignore activation
+ rVal = true;
+ }
+ }
+ }
+
+ // save Kovio tag info
+ if (!rVal)
+ {
+ if ((mLastKovioUidLen = mTechParams[0].param.pk.uid_len) > NFC_KOVIO_MAX_LEN)
+ mLastKovioUidLen = NFC_KOVIO_MAX_LEN;
+ memcpy(mLastKovioUid, mTechParams[0].param.pk.uid, mLastKovioUidLen);
+ }
+ mLastKovioTime = now;
+ ALOGD ("%s: exit, is same Kovio=%d", fn, rVal);
+ return rVal;
+}
+
+/*******************************************************************************
+**
+** Function: discoverTechnologies
+**
+** Description: Discover the technologies that NFC service needs by interpreting
+** the data strucutures from the stack.
+** activationData: data from activation.
+**
+** Returns: None
+**
+*******************************************************************************/
+void NfcTag::discoverTechnologies (tNFA_ACTIVATED& activationData)
+{
+ static const char fn [] = "NfcTag::discoverTechnologies (activation)";
+ ALOGD ("%s: enter", fn);
+ tNFC_ACTIVATE_DEVT& rfDetail = activationData.activate_ntf;
+
+ mNumTechList = 0;
+ mTechHandles [mNumTechList] = rfDetail.rf_disc_id;
+ mTechLibNfcTypes [mNumTechList] = rfDetail.protocol;
+
+ //save the stack's data structure for interpretation later
+ memcpy (&(mTechParams[mNumTechList]), &(rfDetail.rf_tech_param), sizeof(rfDetail.rf_tech_param));
+
+ switch (rfDetail.protocol)
+ {
+ case NFC_PROTOCOL_T1T:
+ mTechList [mNumTechList] = TARGET_TYPE_ISO14443_3A; //is TagTechnology.NFC_A by Java API
+ break;
+
+ case NFC_PROTOCOL_T2T:
+ mTechList [mNumTechList] = TARGET_TYPE_ISO14443_3A; //is TagTechnology.NFC_A by Java API
+ // could be MifFare UL or Classic or Kovio
+ {
+ // need to look at first byte of uid to find manuf.
+ tNFC_RF_TECH_PARAMS tech_params;
+ memcpy (&tech_params, &(rfDetail.rf_tech_param), sizeof(rfDetail.rf_tech_param));
+
+ if ((tech_params.param.pa.nfcid1[0] == 0x04 && rfDetail.rf_tech_param.param.pa.sel_rsp == 0) ||
+ rfDetail.rf_tech_param.param.pa.sel_rsp == 0x18 ||
+ rfDetail.rf_tech_param.param.pa.sel_rsp == 0x08)
+ {
+ if (rfDetail.rf_tech_param.param.pa.sel_rsp == 0)
+ {
+ mNumTechList++;
+ mTechHandles [mNumTechList] = rfDetail.rf_disc_id;
+ mTechLibNfcTypes [mNumTechList] = rfDetail.protocol;
+ //save the stack's data structure for interpretation later
+ memcpy (&(mTechParams[mNumTechList]), &(rfDetail.rf_tech_param), sizeof(rfDetail.rf_tech_param));
+ mTechList [mNumTechList] = TARGET_TYPE_MIFARE_UL; //is TagTechnology.MIFARE_ULTRALIGHT by Java API
+ }
+ }
+ }
+ break;
+
+ case NFC_PROTOCOL_T3T:
+ mTechList [mNumTechList] = TARGET_TYPE_FELICA;
+ break;
+
+ case NFC_PROTOCOL_ISO_DEP: //type-4 tag uses technology ISO-DEP and technology A or B
+ mTechList [mNumTechList] = TARGET_TYPE_ISO14443_4; //is TagTechnology.ISO_DEP by Java API
+ if ( (rfDetail.rf_tech_param.mode == NFC_DISCOVERY_TYPE_POLL_A) ||
+ (rfDetail.rf_tech_param.mode == NFC_DISCOVERY_TYPE_POLL_A_ACTIVE) ||
+ (rfDetail.rf_tech_param.mode == NFC_DISCOVERY_TYPE_LISTEN_A) ||
+ (rfDetail.rf_tech_param.mode == NFC_DISCOVERY_TYPE_LISTEN_A_ACTIVE) )
+ {
+ mNumTechList++;
+ mTechHandles [mNumTechList] = rfDetail.rf_disc_id;
+ mTechLibNfcTypes [mNumTechList] = rfDetail.protocol;
+ mTechList [mNumTechList] = TARGET_TYPE_ISO14443_3A; //is TagTechnology.NFC_A by Java API
+ //save the stack's data structure for interpretation later
+ memcpy (&(mTechParams[mNumTechList]), &(rfDetail.rf_tech_param), sizeof(rfDetail.rf_tech_param));
+ }
+ else if ( (rfDetail.rf_tech_param.mode == NFC_DISCOVERY_TYPE_POLL_B) ||
+ (rfDetail.rf_tech_param.mode == NFC_DISCOVERY_TYPE_POLL_B_PRIME) ||
+ (rfDetail.rf_tech_param.mode == NFC_DISCOVERY_TYPE_LISTEN_B) ||
+ (rfDetail.rf_tech_param.mode == NFC_DISCOVERY_TYPE_LISTEN_B_PRIME) )
+ {
+ mNumTechList++;
+ mTechHandles [mNumTechList] = rfDetail.rf_disc_id;
+ mTechLibNfcTypes [mNumTechList] = rfDetail.protocol;
+ mTechList [mNumTechList] = TARGET_TYPE_ISO14443_3B; //is TagTechnology.NFC_B by Java API
+ //save the stack's data structure for interpretation later
+ memcpy (&(mTechParams[mNumTechList]), &(rfDetail.rf_tech_param), sizeof(rfDetail.rf_tech_param));
+ }
+ break;
+
+ case NFC_PROTOCOL_15693: //is TagTechnology.NFC_V by Java API
+ mTechList [mNumTechList] = TARGET_TYPE_ISO15693;
+ break;
+
+ case NFC_PROTOCOL_KOVIO:
+ ALOGE ("%s: Kovio", fn);
+ mNumTechList--; // no tech classes for Kovio
+ break;
+
+ default:
+ ALOGE ("%s: unknown protocol ????", fn);
+ mTechList [mNumTechList] = TARGET_TYPE_UNKNOWN;
+ break;
+ }
+
+ mNumTechList++;
+ for (int i=0; i < mNumTechList; i++)
+ {
+ ALOGD ("%s: index=%d; tech=%d; handle=%d; nfc type=%d", fn,
+ i, mTechList[i], mTechHandles[i], mTechLibNfcTypes[i]);
+ }
+ ALOGD ("%s: exit", fn);
+}
+
+
+/*******************************************************************************
+**
+** Function: discoverTechnologies
+**
+** Description: Discover the technologies that NFC service needs by interpreting
+** the data strucutures from the stack.
+** discoveryData: data from discovery events(s).
+**
+** Returns: None
+**
+*******************************************************************************/
+void NfcTag::discoverTechnologies (tNFA_DISC_RESULT& discoveryData)
+{
+ static const char fn [] = "NfcTag::discoverTechnologies (discovery)";
+ tNFC_RESULT_DEVT& discovery_ntf = discoveryData.discovery_ntf;
+
+ ALOGD ("%s: enter: rf disc. id=%u; protocol=%u, mNumTechList=%u", fn, discovery_ntf.rf_disc_id, discovery_ntf.protocol, mNumTechList);
+ if (mNumTechList >= MAX_NUM_TECHNOLOGY)
+ {
+ ALOGE ("%s: exceed max=%d", fn, MAX_NUM_TECHNOLOGY);
+ goto TheEnd;
+ }
+ mTechHandles [mNumTechList] = discovery_ntf.rf_disc_id;
+ mTechLibNfcTypes [mNumTechList] = discovery_ntf.protocol;
+
+ //save the stack's data structure for interpretation later
+ memcpy (&(mTechParams[mNumTechList]), &(discovery_ntf.rf_tech_param), sizeof(discovery_ntf.rf_tech_param));
+
+ switch (discovery_ntf.protocol)
+ {
+ case NFC_PROTOCOL_T1T:
+ mTechList [mNumTechList] = TARGET_TYPE_ISO14443_3A; //is TagTechnology.NFC_A by Java API
+ break;
+
+ case NFC_PROTOCOL_T2T:
+ mTechList [mNumTechList] = TARGET_TYPE_ISO14443_3A; //is TagTechnology.NFC_A by Java API
+ //type-2 tags are identitical to Mifare Ultralight, so Ultralight is also discovered
+ if (discovery_ntf.rf_tech_param.param.pa.sel_rsp == 0)
+ {
+ // mifare Ultralight
+ mNumTechList++;
+ mTechHandles [mNumTechList] = discovery_ntf.rf_disc_id;
+ mTechLibNfcTypes [mNumTechList] = discovery_ntf.protocol;
+ mTechList [mNumTechList] = TARGET_TYPE_MIFARE_UL; //is TagTechnology.MIFARE_ULTRALIGHT by Java API
+ }
+
+ //save the stack's data structure for interpretation later
+ memcpy (&(mTechParams[mNumTechList]), &(discovery_ntf.rf_tech_param), sizeof(discovery_ntf.rf_tech_param));
+ break;
+
+ case NFC_PROTOCOL_T3T:
+ mTechList [mNumTechList] = TARGET_TYPE_FELICA;
+ break;
+
+ case NFC_PROTOCOL_ISO_DEP: //type-4 tag uses technology ISO-DEP and technology A or B
+ mTechList [mNumTechList] = TARGET_TYPE_ISO14443_4; //is TagTechnology.ISO_DEP by Java API
+ if ( (discovery_ntf.rf_tech_param.mode == NFC_DISCOVERY_TYPE_POLL_A) ||
+ (discovery_ntf.rf_tech_param.mode == NFC_DISCOVERY_TYPE_POLL_A_ACTIVE) ||
+ (discovery_ntf.rf_tech_param.mode == NFC_DISCOVERY_TYPE_LISTEN_A) ||
+ (discovery_ntf.rf_tech_param.mode == NFC_DISCOVERY_TYPE_LISTEN_A_ACTIVE) )
+ {
+ mNumTechList++;
+ mTechHandles [mNumTechList] = discovery_ntf.rf_disc_id;
+ mTechLibNfcTypes [mNumTechList] = discovery_ntf.protocol;
+ mTechList [mNumTechList] = TARGET_TYPE_ISO14443_3A; //is TagTechnology.NFC_A by Java API
+ //save the stack's data structure for interpretation later
+ memcpy (&(mTechParams[mNumTechList]), &(discovery_ntf.rf_tech_param), sizeof(discovery_ntf.rf_tech_param));
+ }
+ else if ( (discovery_ntf.rf_tech_param.mode == NFC_DISCOVERY_TYPE_POLL_B) ||
+ (discovery_ntf.rf_tech_param.mode == NFC_DISCOVERY_TYPE_POLL_B_PRIME) ||
+ (discovery_ntf.rf_tech_param.mode == NFC_DISCOVERY_TYPE_LISTEN_B) ||
+ (discovery_ntf.rf_tech_param.mode == NFC_DISCOVERY_TYPE_LISTEN_B_PRIME) )
+ {
+ mNumTechList++;
+ mTechHandles [mNumTechList] = discovery_ntf.rf_disc_id;
+ mTechLibNfcTypes [mNumTechList] = discovery_ntf.protocol;
+ mTechList [mNumTechList] = TARGET_TYPE_ISO14443_3B; //is TagTechnology.NFC_B by Java API
+ //save the stack's data structure for interpretation later
+ memcpy (&(mTechParams[mNumTechList]), &(discovery_ntf.rf_tech_param), sizeof(discovery_ntf.rf_tech_param));
+ }
+ break;
+
+ case NFC_PROTOCOL_15693: //is TagTechnology.NFC_V by Java API
+ mTechList [mNumTechList] = TARGET_TYPE_ISO15693;
+ break;
+
+ default:
+ ALOGE ("%s: unknown protocol ????", fn);
+ mTechList [mNumTechList] = TARGET_TYPE_UNKNOWN;
+ break;
+ }
+
+ mNumTechList++;
+ if (discovery_ntf.more == FALSE)
+ {
+ for (int i=0; i < mNumTechList; i++)
+ {
+ ALOGD ("%s: index=%d; tech=%d; handle=%d; nfc type=%d", fn,
+ i, mTechList[i], mTechHandles[i], mTechLibNfcTypes[i]);
+ }
+ }
+
+TheEnd:
+ ALOGD ("%s: exit", fn);
+}
+
+
+/*******************************************************************************
+**
+** Function: createNativeNfcTag
+**
+** Description: Create a brand new Java NativeNfcTag object;
+** fill the objects's member variables with data;
+** notify NFC service;
+** activationData: data from activation.
+**
+** Returns: None
+**
+*******************************************************************************/
+void NfcTag::createNativeNfcTag (tNFA_ACTIVATED& activationData)
+{
+ static const char fn [] = "NfcTag::createNativeNfcTag";
+ ALOGD ("%s: enter", fn);
+ JNIEnv* e = NULL;
+ jclass tag_cls = NULL;
+ jmethodID ctor = NULL;
+ jobject tag = NULL;
+
+ //acquire a pointer to the Java virtual machine
+ mNativeData->vm->AttachCurrentThread (&e, NULL);
+ if (e == NULL)
+ {
+ ALOGE("%s: jni env is null", fn);
+ goto TheEnd;
+ }
+
+ tag_cls = e->GetObjectClass (mNativeData->cached_NfcTag);
+ if (e->ExceptionCheck())
+ {
+ e->ExceptionClear();
+ ALOGE("%s: failed to get class", fn);
+ goto TheEnd;
+ }
+
+ //create a new Java NativeNfcTag object
+ ctor = e->GetMethodID (tag_cls, "<init>", "()V");
+ tag = e->NewObject (tag_cls, ctor);
+
+ //fill NativeNfcTag's mProtocols, mTechList, mTechHandles, mTechLibNfcTypes
+ fillNativeNfcTagMembers1 (e, tag_cls, tag);
+
+ //fill NativeNfcTag's members: mHandle, mConnectedTechnology
+ fillNativeNfcTagMembers2 (e, tag_cls, tag, activationData);
+
+ //fill NativeNfcTag's members: mTechPollBytes
+ fillNativeNfcTagMembers3 (e, tag_cls, tag, activationData);
+
+ //fill NativeNfcTag's members: mTechActBytes
+ fillNativeNfcTagMembers4 (e, tag_cls, tag, activationData);
+
+ //fill NativeNfcTag's members: mUid
+ fillNativeNfcTagMembers5 (e, tag_cls, tag, activationData);
+
+ if (mNativeData->tag != NULL) {
+ e->DeleteGlobalRef (mNativeData->tag);
+ }
+ mNativeData->tag = e->NewGlobalRef (tag);
+
+ //notify NFC service about this new tag
+ ALOGD ("%s: try notify nfc service", fn);
+ e->CallVoidMethod (mNativeData->manager, android::gCachedNfcManagerNotifyNdefMessageListeners, tag);
+ if (e->ExceptionCheck())
+ {
+ e->ExceptionClear();
+ ALOGE ("%s: fail notify nfc service", fn);
+ }
+ e->DeleteLocalRef (tag);
+
+TheEnd:
+ mNativeData->vm->DetachCurrentThread ();
+ ALOGD ("%s: exit", fn);
+}
+
+
+/*******************************************************************************
+**
+** Function: fillNativeNfcTagMembers1
+**
+** Description: Fill NativeNfcTag's members: mProtocols, mTechList, mTechHandles, mTechLibNfcTypes.
+** e: JVM environment.
+** tag_cls: Java NativeNfcTag class.
+** tag: Java NativeNfcTag object.
+**
+** Returns: None
+**
+*******************************************************************************/
+void NfcTag::fillNativeNfcTagMembers1 (JNIEnv* e, jclass tag_cls, jobject tag)
+{
+ static const char fn [] = "NfcTag::fillNativeNfcTagMembers1";
+ ALOGD ("%s", fn);
+ jfieldID f = NULL;
+
+ //create objects that represent NativeNfcTag's member variables
+ jintArray techList = e->NewIntArray (mNumTechList);
+ jintArray handleList = e->NewIntArray (mNumTechList);
+ jintArray typeList = e->NewIntArray (mNumTechList);
+
+ jint* technologies = e->GetIntArrayElements (techList, NULL);
+ jint* handles = e->GetIntArrayElements (handleList, NULL);
+ jint* types = e->GetIntArrayElements (typeList, NULL);
+ for (int i = 0; i < mNumTechList; i++)
+ {
+ mNativeData->tProtocols [i] = mTechLibNfcTypes [i];
+ mNativeData->handles [i] = mTechHandles [i];
+ technologies [i] = mTechList [i];
+ handles [i] = mTechHandles [i];
+ types [i] = mTechLibNfcTypes [i];
+ }
+ e->ReleaseIntArrayElements (techList, technologies, 0);
+ e->ReleaseIntArrayElements (handleList, handles, 0);
+ e->ReleaseIntArrayElements (typeList, types, 0);
+
+ f = e->GetFieldID (tag_cls, "mTechList", "[I");
+ e->SetObjectField (tag, f, techList);
+
+ f = e->GetFieldID (tag_cls, "mTechHandles", "[I");
+ e->SetObjectField (tag, f, handleList);
+
+ f = e->GetFieldID (tag_cls, "mTechLibNfcTypes", "[I");
+ e->SetObjectField (tag, f, typeList);
+}
+
+
+/*******************************************************************************
+**
+** Function: fillNativeNfcTagMembers2
+**
+** Description: Fill NativeNfcTag's members: mConnectedTechIndex or mConnectedTechnology.
+** The original Google's implementation is in set_target_pollBytes(
+** in com_android_nfc_NativeNfcTag.cpp;
+** e: JVM environment.
+** tag_cls: Java NativeNfcTag class.
+** tag: Java NativeNfcTag object.
+** activationData: data from activation.
+**
+** Returns: None
+**
+*******************************************************************************/
+//fill NativeNfcTag's members: mHandle, mConnectedTechnology
+void NfcTag::fillNativeNfcTagMembers2 (JNIEnv* e, jclass tag_cls, jobject tag, tNFA_ACTIVATED& activationData)
+{
+ static const char fn [] = "NfcTag::fillNativeNfcTagMembers2";
+ ALOGD ("%s", fn);
+ jfieldID f = NULL;
+
+ f = e->GetFieldID (tag_cls, "mConnectedTechIndex", "I");
+ e->SetIntField (tag, f, (jint) 0);
+}
+
+
+/*******************************************************************************
+**
+** Function: fillNativeNfcTagMembers3
+**
+** Description: Fill NativeNfcTag's members: mTechPollBytes.
+** The original Google's implementation is in set_target_pollBytes(
+** in com_android_nfc_NativeNfcTag.cpp;
+** e: JVM environment.
+** tag_cls: Java NativeNfcTag class.
+** tag: Java NativeNfcTag object.
+** activationData: data from activation.
+**
+** Returns: None
+**
+*******************************************************************************/
+void NfcTag::fillNativeNfcTagMembers3 (JNIEnv* e, jclass tag_cls, jobject tag, tNFA_ACTIVATED& activationData)
+{
+ static const char fn [] = "NfcTag::fillNativeNfcTagMembers3";
+ jfieldID f = NULL;
+ jbyteArray pollBytes = e->NewByteArray (0);
+ jobjectArray techPollBytes = e->NewObjectArray (mNumTechList, e->GetObjectClass(pollBytes), 0);
+ int len = 0;
+
+ for (int i = 0; i < mNumTechList; i++)
+ {
+ ALOGD ("%s: index=%d; rf tech params mode=%u", fn, i, mTechParams [i].mode);
+ switch (mTechParams [i].mode)
+ {
+ case NFC_DISCOVERY_TYPE_POLL_A:
+ case NFC_DISCOVERY_TYPE_POLL_A_ACTIVE:
+ case NFC_DISCOVERY_TYPE_LISTEN_A:
+ case NFC_DISCOVERY_TYPE_LISTEN_A_ACTIVE:
+ ALOGD ("%s: tech A", fn);
+ pollBytes = e->NewByteArray (2);
+ e->SetByteArrayRegion (pollBytes, 0, 2,
+ (jbyte*) mTechParams [i].param.pa.sens_res);
+ break;
+
+ case NFC_DISCOVERY_TYPE_POLL_B:
+ case NFC_DISCOVERY_TYPE_POLL_B_PRIME:
+ case NFC_DISCOVERY_TYPE_LISTEN_B:
+ case NFC_DISCOVERY_TYPE_LISTEN_B_PRIME:
+ if (mTechList [i] == TARGET_TYPE_ISO14443_3B) //is TagTechnology.NFC_B by Java API
+ {
+ /*****************
+ see NFC Forum Digital Protocol specification; section 5.6.2;
+ in SENSB_RES response, byte 6 through 9 is Application Data, byte 10-12 or 13 is Protocol Info;
+ used by public API: NfcB.getApplicationData(), NfcB.getProtocolInfo();
+ *****************/
+ ALOGD ("%s: tech B; TARGET_TYPE_ISO14443_3B", fn);
+ len = mTechParams [i].param.pb.sensb_res_len;
+ len = len - 4; //subtract 4 bytes for NFCID0 at byte 2 through 5
+ pollBytes = e->NewByteArray (len);
+ e->SetByteArrayRegion (pollBytes, 0, len, (jbyte*) (mTechParams [i].param.pb.sensb_res+4));
+ }
+ else
+ pollBytes = e->NewByteArray (0);
+ break;
+
+ case NFC_DISCOVERY_TYPE_POLL_F:
+ case NFC_DISCOVERY_TYPE_POLL_F_ACTIVE:
+ case NFC_DISCOVERY_TYPE_LISTEN_F:
+ case NFC_DISCOVERY_TYPE_LISTEN_F_ACTIVE:
+ {
+ /****************
+ see NFC Forum Type 3 Tag Operation Specification; sections 2.3.2, 2.3.1.2;
+ see NFC Forum Digital Protocol Specification; sections 6.6.2;
+ PMm: manufacture parameter; 8 bytes;
+ System Code: 2 bytes;
+ ****************/
+ ALOGD ("%s: tech F", fn);
+ UINT8 result [10]; //return result to NFC service
+ memset (result, 0, sizeof(result));
+ len = 10;
+
+ /****
+ for (int ii = 0; ii < mTechParams [i].param.pf.sensf_res_len; ii++)
+ {
+ ALOGD ("%s: tech F, sendf_res[%d]=%d (0x%x)",
+ fn, ii, mTechParams [i].param.pf.sensf_res[ii],mTechParams [i].param.pf.sensf_res[ii]);
+ }
+ ***/
+ memcpy (result, mTechParams [i].param.pf.sensf_res + 8, 8); //copy PMm
+ if (activationData.params.t3t.num_system_codes > 0) //copy the first System Code
+ {
+ UINT16 systemCode = *(activationData.params.t3t.p_system_codes);
+ result [8] = (UINT8) (systemCode >> 8);
+ result [9] = (UINT8) systemCode;
+ ALOGD ("%s: tech F; sys code=0x%X 0x%X", fn, result [8], result [9]);
+ }
+ pollBytes = e->NewByteArray (len);
+ e->SetByteArrayRegion (pollBytes, 0, len, (jbyte*) result);
+ }
+ break;
+
+ case NFC_DISCOVERY_TYPE_POLL_ISO15693:
+ case NFC_DISCOVERY_TYPE_LISTEN_ISO15693:
+ {
+ ALOGD ("%s: tech iso 15693", fn);
+ //iso 15693 response flags: 1 octet
+ //iso 15693 Data Structure Format Identifier (DSF ID): 1 octet
+ //used by public API: NfcV.getDsfId(), NfcV.getResponseFlags();
+ uint8_t data [2]= {activationData.params.i93.afi, activationData.params.i93.dsfid};
+ pollBytes = e->NewByteArray (2);
+ e->SetByteArrayRegion (pollBytes, 0, 2, (jbyte *) data);
+ }
+ break;
+
+ default:
+ ALOGE ("%s: tech unknown ????", fn);
+ pollBytes = e->NewByteArray(0);
+ break;
+ } //switch: every type of technology
+ e->SetObjectArrayElement (techPollBytes, i, pollBytes);
+ } //for: every technology in the array
+ f = e->GetFieldID (tag_cls, "mTechPollBytes", "[[B");
+ e->SetObjectField (tag, f, techPollBytes);
+}
+
+
+/*******************************************************************************
+**
+** Function: fillNativeNfcTagMembers4
+**
+** Description: Fill NativeNfcTag's members: mTechActBytes.
+** The original Google's implementation is in set_target_activationBytes()
+** in com_android_nfc_NativeNfcTag.cpp;
+** e: JVM environment.
+** tag_cls: Java NativeNfcTag class.
+** tag: Java NativeNfcTag object.
+** activationData: data from activation.
+**
+** Returns: None
+**
+*******************************************************************************/
+void NfcTag::fillNativeNfcTagMembers4 (JNIEnv* e, jclass tag_cls, jobject tag, tNFA_ACTIVATED& activationData)
+{
+ static const char fn [] = "NfcTag::fillNativeNfcTagMembers4";
+ jfieldID f = NULL;
+ jbyteArray actBytes = e->NewByteArray (0);
+ jobjectArray techActBytes = e->NewObjectArray (mNumTechList, e->GetObjectClass(actBytes), 0);
+ jbyteArray uid = NULL;
+ int len = 0;
+
+ for (int i = 0; i < mNumTechList; i++)
+ {
+ ALOGD ("%s: index=%d", fn, i);
+ switch (mTechLibNfcTypes[i])
+ {
+ case NFC_PROTOCOL_T1T:
+ {
+ ALOGD ("%s: T1T; tech A", fn);
+ actBytes = e->NewByteArray (1);
+ e->SetByteArrayRegion (actBytes, 0, 1,
+ (jbyte*) &mTechParams [i].param.pa.sel_rsp);
+ }
+ break;
+
+ case NFC_PROTOCOL_T2T:
+ {
+ ALOGD ("%s: T2T; tech A", fn);
+ actBytes = e->NewByteArray (1);
+ e->SetByteArrayRegion (actBytes, 0, 1,
+ (jbyte*) &mTechParams [i].param.pa.sel_rsp);
+ }
+ break;
+
+ case NFC_PROTOCOL_T3T: //felica
+ {
+ ALOGD ("%s: T3T; felica; tech F", fn);
+ //really, there is no data
+ actBytes = e->NewByteArray (0);
+ }
+ break;
+
+ case NFC_PROTOCOL_ISO_DEP: //t4t
+ {
+ if (mTechList [i] == TARGET_TYPE_ISO14443_4) //is TagTechnology.ISO_DEP by Java API
+ {
+ if ( (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_A) ||
+ (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_A_ACTIVE) ||
+ (mTechParams[i].mode == NFC_DISCOVERY_TYPE_LISTEN_A) ||
+ (mTechParams[i].mode == NFC_DISCOVERY_TYPE_LISTEN_A_ACTIVE) )
+ {
+ //see NFC Forum Digital Protocol specification, section 11.6.2, "RATS Response"; search for "historical bytes";
+ //copy historical bytes into Java object;
+ //the public API, IsoDep.getHistoricalBytes(), returns this data;
+ if (activationData.activate_ntf.intf_param.type == NFC_INTERFACE_ISO_DEP)
+ {
+ tNFC_INTF_PA_ISO_DEP& pa_iso = activationData.activate_ntf.intf_param.intf_param.pa_iso;
+ ALOGD ("%s: T4T; ISO_DEP for tech A; copy historical bytes; len=%u", fn, pa_iso.his_byte_len);
+ actBytes = e->NewByteArray (pa_iso.his_byte_len);
+ if (pa_iso.his_byte_len > 0)
+ e->SetByteArrayRegion (actBytes, 0, pa_iso.his_byte_len, (jbyte*) (pa_iso.his_byte));
+ }
+ else
+ {
+ ALOGE ("%s: T4T; ISO_DEP for tech A; wrong interface=%u", fn, activationData.activate_ntf.intf_param.type);
+ actBytes = e->NewByteArray (0);
+ }
+ }
+ else if ( (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_B) ||
+ (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_B_PRIME) ||
+ (mTechParams[i].mode == NFC_DISCOVERY_TYPE_LISTEN_B) ||
+ (mTechParams[i].mode == NFC_DISCOVERY_TYPE_LISTEN_B_PRIME) )
+ {
+ //see NFC Forum Digital Protocol specification, section 12.6.2, "ATTRIB Response";
+ //copy higher-layer response bytes into Java object;
+ //the public API, IsoDep.getHiLayerResponse(), returns this data;
+ if (activationData.activate_ntf.intf_param.type == NFC_INTERFACE_ISO_DEP)
+ {
+ tNFC_INTF_PB_ISO_DEP& pb_iso = activationData.activate_ntf.intf_param.intf_param.pb_iso;
+ ALOGD ("%s: T4T; ISO_DEP for tech B; copy response bytes; len=%u", fn, pb_iso.hi_info_len);
+ actBytes = e->NewByteArray (pb_iso.hi_info_len);
+ if (pb_iso.hi_info_len > 0)
+ e->SetByteArrayRegion (actBytes, 0, pb_iso.hi_info_len, (jbyte*) (pb_iso.hi_info));
+ }
+ else
+ {
+ ALOGE ("%s: T4T; ISO_DEP for tech B; wrong interface=%u", fn, activationData.activate_ntf.intf_param.type);
+ actBytes = e->NewByteArray (0);
+ }
+ }
+ }
+ else if (mTechList [i] == TARGET_TYPE_ISO14443_3A) //is TagTechnology.NFC_A by Java API
+ {
+ ALOGD ("%s: T4T; tech A", fn);
+ actBytes = e->NewByteArray (1);
+ e->SetByteArrayRegion (actBytes, 0, 1, (jbyte*) &mTechParams [i].param.pa.sel_rsp);
+ }
+ else
+ {
+ actBytes = e->NewByteArray (0);
+ }
+ } //case NFC_PROTOCOL_ISO_DEP: //t4t
+ break;
+
+ case NFC_PROTOCOL_15693:
+ {
+ ALOGD ("%s: tech iso 15693", fn);
+ //iso 15693 response flags: 1 octet
+ //iso 15693 Data Structure Format Identifier (DSF ID): 1 octet
+ //used by public API: NfcV.getDsfId(), NfcV.getResponseFlags();
+ uint8_t data [2]= {activationData.params.i93.afi, activationData.params.i93.dsfid};
+ actBytes = e->NewByteArray (2);
+ e->SetByteArrayRegion (actBytes, 0, 2, (jbyte *) data);
+ }
+ break;
+
+ default:
+ ALOGD ("%s: tech unknown ????", fn);
+ actBytes = e->NewByteArray (0);
+ break;
+ }//switch
+ e->SetObjectArrayElement (techActBytes, i, actBytes);
+ } //for: every technology in the array
+ f = e->GetFieldID (tag_cls, "mTechActBytes", "[[B");
+ e->SetObjectField (tag, f, techActBytes);
+}
+
+
+/*******************************************************************************
+**
+** Function: fillNativeNfcTagMembers5
+**
+** Description: Fill NativeNfcTag's members: mUid.
+** The original Google's implementation is in nfc_jni_Discovery_notification_callback()
+** in com_android_nfc_NativeNfcManager.cpp;
+** e: JVM environment.
+** tag_cls: Java NativeNfcTag class.
+** tag: Java NativeNfcTag object.
+** activationData: data from activation.
+**
+** Returns: None
+**
+*******************************************************************************/
+void NfcTag::fillNativeNfcTagMembers5 (JNIEnv* e, jclass tag_cls, jobject tag, tNFA_ACTIVATED& activationData)
+{
+ static const char fn [] = "NfcTag::fillNativeNfcTagMembers5";
+ jfieldID f = NULL;
+ int len = 0;
+ jbyteArray uid = NULL;
+
+ switch (mTechParams [0].mode)
+ {
+ case NFC_DISCOVERY_TYPE_POLL_KOVIO:
+ ALOGD ("%s: Kovio", fn);
+ len = mTechParams [0].param.pk.uid_len;
+ uid = e->NewByteArray (len);
+ e->SetByteArrayRegion (uid, 0, len,
+ (jbyte*) &mTechParams [0].param.pk.uid);
+ break;
+
+ case NFC_DISCOVERY_TYPE_POLL_A:
+ case NFC_DISCOVERY_TYPE_POLL_A_ACTIVE:
+ case NFC_DISCOVERY_TYPE_LISTEN_A:
+ case NFC_DISCOVERY_TYPE_LISTEN_A_ACTIVE:
+ ALOGD ("%s: tech A", fn);
+ len = mTechParams [0].param.pa.nfcid1_len;
+ uid = e->NewByteArray (len);
+ e->SetByteArrayRegion (uid, 0, len,
+ (jbyte*) &mTechParams [0].param.pa.nfcid1);
+ break;
+
+ case NFC_DISCOVERY_TYPE_POLL_B:
+ case NFC_DISCOVERY_TYPE_POLL_B_PRIME:
+ case NFC_DISCOVERY_TYPE_LISTEN_B:
+ case NFC_DISCOVERY_TYPE_LISTEN_B_PRIME:
+ ALOGD ("%s: tech B", fn);
+ uid = e->NewByteArray (NFC_NFCID0_MAX_LEN);
+ e->SetByteArrayRegion (uid, 0, NFC_NFCID0_MAX_LEN,
+ (jbyte*) &mTechParams [0].param.pb.nfcid0);
+ break;
+
+ case NFC_DISCOVERY_TYPE_POLL_F:
+ case NFC_DISCOVERY_TYPE_POLL_F_ACTIVE:
+ case NFC_DISCOVERY_TYPE_LISTEN_F:
+ case NFC_DISCOVERY_TYPE_LISTEN_F_ACTIVE:
+ ALOGD ("%s: tech F", fn);
+ uid = e->NewByteArray (NFC_NFCID2_LEN);
+ e->SetByteArrayRegion (uid, 0, NFC_NFCID2_LEN,
+ (jbyte*) &mTechParams [0].param.pf.nfcid2);
+ break;
+
+ case NFC_DISCOVERY_TYPE_POLL_ISO15693:
+ case NFC_DISCOVERY_TYPE_LISTEN_ISO15693:
+ {
+ ALOGD ("%s: tech iso 15693", fn);
+ jbyte data [I93_UID_BYTE_LEN]; //8 bytes
+ for (int i=0; i<I93_UID_BYTE_LEN; ++i) //reverse the ID
+ data[i] = activationData.params.i93.uid [I93_UID_BYTE_LEN - i - 1];
+ uid = e->NewByteArray (I93_UID_BYTE_LEN);
+ e->SetByteArrayRegion (uid, 0, I93_UID_BYTE_LEN, data);
+ }
+ break;
+
+ default:
+ ALOGE ("%s: tech unknown ????", fn);
+ uid = e->NewByteArray (0);
+ break;
+ } //if
+ f = e->GetFieldID(tag_cls, "mUid", "[B");
+ e->SetObjectField(tag, f, uid);
+}
+
+
+/*******************************************************************************
+**
+** Function: isP2pDiscovered
+**
+** Description: Does the peer support P2P?
+**
+** Returns: True if the peer supports P2P.
+**
+*******************************************************************************/
+bool NfcTag::isP2pDiscovered ()
+{
+ static const char fn [] = "NfcTag::isP2pDiscovered";
+ bool retval = false;
+
+ for (int i = 0; i < mNumTechList; i++)
+ {
+ if (mTechLibNfcTypes[i] == NFA_PROTOCOL_NFC_DEP)
+ {
+ //if remote device supports P2P
+ ALOGD ("%s: discovered P2P", fn);
+ retval = true;
+ break;
+ }
+ }
+ ALOGD ("%s: return=%u", fn, retval);
+ return retval;
+}
+
+
+/*******************************************************************************
+**
+** Function: selectP2p
+**
+** Description: Select the preferred P2P technology if there is a choice.
+**
+** Returns: None
+**
+*******************************************************************************/
+void NfcTag::selectP2p()
+{
+ static const char fn [] = "NfcTag::selectP2p";
+ UINT8 rfDiscoveryId = 0;
+
+ for (int i = 0; i < mNumTechList; i++)
+ {
+ //if remote device does not support P2P, just skip it
+ if (mTechLibNfcTypes[i] != NFA_PROTOCOL_NFC_DEP)
+ continue;
+
+ //if remote device supports tech F;
+ //tech F is preferred because it is faster than tech A
+ if ( (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_F) ||
+ (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_F_ACTIVE) )
+ {
+ rfDiscoveryId = mTechHandles[i];
+ break; //no need to search further
+ }
+ else if ( (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_A) ||
+ (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_A_ACTIVE) )
+ {
+ //only choose tech A if tech F is unavailable
+ if (rfDiscoveryId == 0)
+ rfDiscoveryId = mTechHandles[i];
+ }
+ }
+
+ if (rfDiscoveryId > 0)
+ {
+ ALOGD ("%s: select P2P; target rf discov id=0x%X", fn, rfDiscoveryId);
+ tNFA_STATUS stat = NFA_Select (rfDiscoveryId, NFA_PROTOCOL_NFC_DEP, NFA_INTERFACE_NFC_DEP);
+ if (stat != NFA_STATUS_OK)
+ ALOGE ("%s: fail select P2P; error=0x%X", fn, stat);
+ }
+ else
+ ALOGE ("%s: cannot find P2P", fn);
+ resetTechnologies ();
+}
+
+
+/*******************************************************************************
+**
+** Function: resetTechnologies
+**
+** Description: Clear all data related to the technology, protocol of the tag.
+**
+** Returns: None
+**
+*******************************************************************************/
+void NfcTag::resetTechnologies ()
+{
+ static const char fn [] = "NfcTag::resetTechnologies";
+ ALOGD ("%s", fn);
+ mNumTechList = 0;
+ memset (mTechList, 0, sizeof(mTechList));
+ memset (mTechHandles, 0, sizeof(mTechHandles));
+ memset (mTechLibNfcTypes, 0, sizeof(mTechLibNfcTypes));
+ memset (mTechParams, 0, sizeof(mTechParams));
+}
+
+
+/*******************************************************************************
+**
+** Function: selectFirstTag
+**
+** Description: When multiple tags are discovered, just select the first one to activate.
+**
+** Returns: None
+**
+*******************************************************************************/
+void NfcTag::selectFirstTag ()
+{
+ static const char fn [] = "NfcTag::selectFirstTag";
+ ALOGD ("%s: nfa target h=0x%X; protocol=0x%X",
+ fn, mTechHandles [0], mTechLibNfcTypes [0]);
+ tNFA_INTF_TYPE rf_intf = NFA_INTERFACE_FRAME;
+
+ if (mTechLibNfcTypes [0] == NFA_PROTOCOL_ISO_DEP)
+ {
+ rf_intf = NFA_INTERFACE_ISO_DEP;
+ }
+ else if (mTechLibNfcTypes [0] == NFA_PROTOCOL_NFC_DEP)
+ rf_intf = NFA_INTERFACE_NFC_DEP;
+ else
+ rf_intf = NFA_INTERFACE_FRAME;
+
+ tNFA_STATUS stat = NFA_Select (mTechHandles [0], mTechLibNfcTypes [0], rf_intf);
+ if (stat != NFA_STATUS_OK)
+ ALOGE ("%s: fail select; error=0x%X", fn, stat);
+}
+
+
+/*******************************************************************************
+**
+** Function: getT1tMaxMessageSize
+**
+** Description: Get the maximum size (octet) that a T1T can store.
+**
+** Returns: Maximum size in octets.
+**
+*******************************************************************************/
+int NfcTag::getT1tMaxMessageSize ()
+{
+ static const char fn [] = "NfcTag::getT1tMaxMessageSize";
+
+ if (mProtocol != NFC_PROTOCOL_T1T)
+ {
+ ALOGE ("%s: wrong protocol %u", fn, mProtocol);
+ return 0;
+ }
+ return mtT1tMaxMessageSize;
+}
+
+
+/*******************************************************************************
+**
+** Function: calculateT1tMaxMessageSize
+**
+** Description: Calculate type-1 tag's max message size based on header ROM bytes.
+** activate: reference to activation data.
+**
+** Returns: None
+**
+*******************************************************************************/
+void NfcTag::calculateT1tMaxMessageSize (tNFA_ACTIVATED& activate)
+{
+ static const char fn [] = "NfcTag::calculateT1tMaxMessageSize";
+
+ //make sure the tag is type-1
+ if (activate.activate_ntf.protocol != NFC_PROTOCOL_T1T)
+ {
+ mtT1tMaxMessageSize = 0;
+ return;
+ }
+
+ //examine the first byte of header ROM bytes
+ switch (activate.params.t1t.hr[0])
+ {
+ case RW_T1T_IS_TOPAZ96:
+ mtT1tMaxMessageSize = 90;
+ break;
+ case RW_T1T_IS_TOPAZ512:
+ mtT1tMaxMessageSize = 462;
+ break;
+ default:
+ ALOGE ("%s: unknown T1T HR0=%u", fn, activate.params.t1t.hr[0]);
+ mtT1tMaxMessageSize = 0;
+ break;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: isMifareUltralight
+**
+** Description: Whether the currently activated tag is Mifare Ultralight.
+**
+** Returns: True if tag is Mifare Ultralight.
+**
+*******************************************************************************/
+bool NfcTag::isMifareUltralight ()
+{
+ static const char fn [] = "NfcTag::isMifareUltralight";
+ bool retval = false;
+
+ for (int i =0; i < mNumTechList; i++)
+ {
+ if ( (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_A) ||
+ (mTechParams[i].mode == NFC_DISCOVERY_TYPE_LISTEN_A) ||
+ (mTechParams[i].mode == NFC_DISCOVERY_TYPE_LISTEN_A_ACTIVE) )
+ {
+ //see NFC Digital Protocol, section 4.6.3 (SENS_RES); section 4.8.2 (SEL_RES).
+ //see Mifare Type Identification Procedure, section 5.1 (ATQA), 5.2 (SAK).
+ if ( (mTechParams[i].param.pa.sens_res[0] == 0x44) &&
+ (mTechParams[i].param.pa.sens_res[1] == 0) )
+ {
+ // SyncEventGuard g (mReadCompleteEvent);
+ // mReadCompletedStatus = NFA_STATUS_BUSY;
+ // ALOGD ("%s: read block 0x10", fn);
+ // tNFA_STATUS stat = NFA_RwT2tRead (0x10);
+ // if (stat == NFA_STATUS_OK)
+ // mReadCompleteEvent.wait ();
+ //
+ // //if read-completion status is failure, then the tag is
+ // //definitely Mifare Ultralight;
+ // //if read-completion status is OK, then the tag is
+ // //definitely Mifare Ultralight C;
+ // retval = (mReadCompletedStatus == NFA_STATUS_FAILED);
+ retval = true;
+ }
+ break;
+ }
+ }
+ ALOGD ("%s: return=%u", fn, retval);
+ return retval;
+}
+
+
+/*******************************************************************************
+**
+** Function: isT2tNackResponse
+**
+** Description: Whether the response is a T2T NACK response.
+** See NFC Digital Protocol Technical Specification (2010-11-17).
+** Chapter 9 (Type 2 Tag Platform), section 9.6 (READ).
+** response: buffer contains T2T response.
+** responseLen: length of the response.
+**
+** Returns: True if the response is NACK
+**
+*******************************************************************************/
+bool NfcTag::isT2tNackResponse (const UINT8* response, UINT32 responseLen)
+{
+ static const char fn [] = "NfcTag::isT2tNackResponse";
+ bool isNack = false;
+
+ if (responseLen == 1)
+ {
+ if (response[0] == 0xA)
+ isNack = false; //an ACK response, so definitely not a NACK
+ else
+ isNack = true; //assume every value is a NACK
+ }
+ ALOGD ("%s: return %u", fn, isNack);
+ return isNack;
+}
+
+
+/*******************************************************************************
+**
+** Function: isNdefDetectionTimedOut
+**
+** Description: Whether NDEF-detection algorithm timed out.
+**
+** Returns: True if NDEF-detection algorithm timed out.
+**
+*******************************************************************************/
+bool NfcTag::isNdefDetectionTimedOut ()
+{
+ return mNdefDetectionTimedOut;
+}
+
+
+/*******************************************************************************
+**
+** Function: connectionEventHandler
+**
+** Description: Handle connection-related events.
+** event: event code.
+** data: pointer to event data.
+**
+** Returns: None
+**
+*******************************************************************************/
+void NfcTag::connectionEventHandler (UINT8 event, tNFA_CONN_EVT_DATA* data)
+{
+ static const char fn [] = "NfcTag::connectionEventHandler";
+
+ switch (event)
+ {
+ case NFA_DISC_RESULT_EVT:
+ {
+ tNFA_DISC_RESULT& disc_result = data->disc_result;
+ if (disc_result.status == NFA_STATUS_OK)
+ {
+ discoverTechnologies (disc_result);
+ }
+ }
+ break;
+
+ case NFA_ACTIVATED_EVT:
+ // Only do tag detection if we are polling and it is not 'EE Direct RF' activation
+ // (which may happen when we are activated as a tag).
+ if (data->activated.activate_ntf.rf_tech_param.mode < NCI_DISCOVERY_TYPE_LISTEN_A
+ && data->activated.activate_ntf.intf_param.type != NFC_INTERFACE_EE_DIRECT_RF)
+ {
+ tNFA_ACTIVATED& activated = data->activated;
+ if (IsSameKovio(activated))
+ break;
+ mProtocol = activated.activate_ntf.protocol;
+ calculateT1tMaxMessageSize (activated);
+ discoverTechnologies (activated);
+ createNativeNfcTag (activated);
+ }
+ break;
+
+ case NFA_DEACTIVATED_EVT:
+ mProtocol = NFC_PROTOCOL_UNKNOWN;
+ resetTechnologies ();
+ break;
+
+ case NFA_READ_CPLT_EVT:
+ {
+ SyncEventGuard g (mReadCompleteEvent);
+ mReadCompletedStatus = data->status;
+ mReadCompleteEvent.notifyOne ();
+ }
+ break;
+
+ case NFA_NDEF_DETECT_EVT:
+ {
+ tNFA_NDEF_DETECT& ndef_detect = data->ndef_detect;
+ mNdefDetectionTimedOut = ndef_detect.status == NFA_STATUS_TIMEOUT;
+ if (mNdefDetectionTimedOut)
+ ALOGE ("%s: NDEF detection timed out", fn);
+ }
+ }
+}
+
diff --git a/nci/jni/NfcTag.h b/nci/jni/NfcTag.h
new file mode 100755
index 0000000..7fa56ee
--- /dev/null
+++ b/nci/jni/NfcTag.h
@@ -0,0 +1,419 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+/*
+ * Tag-reading, tag-writing operations.
+ */
+
+#pragma once
+#include "SyncEvent.h"
+#include "NfcJniUtil.h"
+extern "C"
+{
+ #include "nfa_rw_api.h"
+}
+
+
+class NfcTag
+{
+public:
+ enum ActivationState {Idle, Sleep, Active};
+ static const int MAX_NUM_TECHNOLOGY = 10; //max number of technologies supported by one or more tags
+ int mTechList [MAX_NUM_TECHNOLOGY]; //array of NFC technologies according to NFC service
+ int mTechHandles [MAX_NUM_TECHNOLOGY]; //array of tag handles according to NFC service
+ int mTechLibNfcTypes [MAX_NUM_TECHNOLOGY]; //array of detailed tag types according to NFC service
+ int mNumTechList; //current number of NFC technologies in the list
+
+ /*******************************************************************************
+ **
+ ** Function: NfcTag
+ **
+ ** Description: Initialize member variables.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ NfcTag ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: getInstance
+ **
+ ** Description: Get a reference to the singleton NfcTag object.
+ **
+ ** Returns: Reference to NfcTag object.
+ **
+ *******************************************************************************/
+ static NfcTag& getInstance ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: initialize
+ **
+ ** Description: Reset member variables.
+ ** native: Native data.
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void initialize (nfc_jni_native_data* native);
+
+
+ /*******************************************************************************
+ **
+ ** Function: abort
+ **
+ ** Description: Unblock all operations.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void abort ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: connectionEventHandler
+ **
+ ** Description: Handle connection-related events.
+ ** event: event code.
+ ** data: pointer to event data.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void connectionEventHandler (UINT8 event, tNFA_CONN_EVT_DATA* data);
+
+
+ /*******************************************************************************
+ **
+ ** Function: getActivationState
+ **
+ ** Description: What is the current state: Idle, Sleep, or Activated.
+ **
+ ** Returns: Idle, Sleep, or Activated.
+ **
+ *******************************************************************************/
+ ActivationState getActivationState ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: setDeactivationState
+ **
+ ** Description: Set the current state: Idle or Sleep.
+ ** deactivated: state of deactivation.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ void setDeactivationState (tNFA_DEACTIVATED& deactivated);
+
+
+ /*******************************************************************************
+ **
+ ** Function: setActivationState
+ **
+ ** Description: Set the current state to Active.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ void setActivationState ();
+
+ /*******************************************************************************
+ **
+ ** Function: getProtocol
+ **
+ ** Description: Get the protocol of the current tag.
+ **
+ ** Returns: Protocol number.
+ **
+ *******************************************************************************/
+ tNFC_PROTOCOL getProtocol ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: isP2pDiscovered
+ **
+ ** Description: Does the peer support P2P?
+ **
+ ** Returns: True if the peer supports P2P.
+ **
+ *******************************************************************************/
+ bool isP2pDiscovered ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: selectP2p
+ **
+ ** Description: Select the preferred P2P technology if there is a choice.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void selectP2p ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: selectFirstTag
+ **
+ ** Description: When multiple tags are discovered, just select the first one to activate.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void selectFirstTag ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: getT1tMaxMessageSize
+ **
+ ** Description: Get the maximum size (octet) that a T1T can store.
+ **
+ ** Returns: Maximum size in octets.
+ **
+ *******************************************************************************/
+ int getT1tMaxMessageSize ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: isMifareUltralight
+ **
+ ** Description: Whether the currently activated tag is Mifare Ultralight.
+ **
+ ** Returns: True if tag is Mifare Ultralight.
+ **
+ *******************************************************************************/
+ bool isMifareUltralight ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: isT2tNackResponse
+ **
+ ** Description: Whether the response is a T2T NACK response.
+ ** See NFC Digital Protocol Technical Specification (2010-11-17).
+ ** Chapter 9 (Type 2 Tag Platform), section 9.6 (READ).
+ ** response: buffer contains T2T response.
+ ** responseLen: length of the response.
+ **
+ ** Returns: True if the response is NACK
+ **
+ *******************************************************************************/
+ bool isT2tNackResponse (const UINT8* response, UINT32 responseLen);
+
+ /*******************************************************************************
+ **
+ ** Function: isNdefDetectionTimedOut
+ **
+ ** Description: Whether NDEF-detection algorithm has timed out.
+ **
+ ** Returns: True if NDEF-detection algorithm timed out.
+ **
+ *******************************************************************************/
+ bool isNdefDetectionTimedOut ();
+
+private:
+ nfc_jni_native_data* mNativeData;
+ ActivationState mActivationState;
+ tNFC_PROTOCOL mProtocol;
+ int mtT1tMaxMessageSize; //T1T max NDEF message size
+ tNFA_STATUS mReadCompletedStatus;
+ int mLastKovioUidLen; // len of uid of last Kovio tag activated
+ bool mNdefDetectionTimedOut; // whether NDEF detection algorithm timed out
+ tNFC_RF_TECH_PARAMS mTechParams [MAX_NUM_TECHNOLOGY]; //array of technology parameters
+ SyncEvent mReadCompleteEvent;
+ struct timespec mLastKovioTime; // time of last Kovio tag activation
+ UINT8 mLastKovioUid[NFC_KOVIO_MAX_LEN]; // uid of last Kovio tag activated
+
+
+ /*******************************************************************************
+ **
+ ** Function: IsSameKovio
+ **
+ ** Description: Checks if tag activate is the same (UID) Kovio tag previously
+ ** activated. This is needed due to a problem with some Kovio
+ ** tags re-activating multiple times.
+ ** activationData: data from activation.
+ **
+ ** Returns: true if the activation is from the same tag previously
+ ** activated, false otherwise
+ **
+ *******************************************************************************/
+ bool IsSameKovio(tNFA_ACTIVATED& activationData);
+
+ /*******************************************************************************
+ **
+ ** Function: discoverTechnologies
+ **
+ ** Description: Discover the technologies that NFC service needs by interpreting
+ ** the data strucutures from the stack.
+ ** activationData: data from activation.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void discoverTechnologies (tNFA_ACTIVATED& activationData);
+
+
+ /*******************************************************************************
+ **
+ ** Function: discoverTechnologies
+ **
+ ** Description: Discover the technologies that NFC service needs by interpreting
+ ** the data strucutures from the stack.
+ ** discoveryData: data from discovery events(s).
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void discoverTechnologies (tNFA_DISC_RESULT& discoveryData);
+
+
+ /*******************************************************************************
+ **
+ ** Function: createNativeNfcTag
+ **
+ ** Description: Create a brand new Java NativeNfcTag object;
+ ** fill the objects's member variables with data;
+ ** notify NFC service;
+ ** activationData: data from activation.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void createNativeNfcTag (tNFA_ACTIVATED& activationData);
+
+
+ /*******************************************************************************
+ **
+ ** Function: fillNativeNfcTagMembers1
+ **
+ ** Description: Fill NativeNfcTag's members: mProtocols, mTechList, mTechHandles, mTechLibNfcTypes.
+ ** e: JVM environment.
+ ** tag_cls: Java NativeNfcTag class.
+ ** tag: Java NativeNfcTag object.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void fillNativeNfcTagMembers1 (JNIEnv* e, jclass tag_cls, jobject tag);
+
+
+ /*******************************************************************************
+ **
+ ** Function: fillNativeNfcTagMembers2
+ **
+ ** Description: Fill NativeNfcTag's members: mConnectedTechIndex or mConnectedTechnology.
+ ** The original Google's implementation is in set_target_pollBytes(
+ ** in com_android_nfc_NativeNfcTag.cpp;
+ ** e: JVM environment.
+ ** tag_cls: Java NativeNfcTag class.
+ ** tag: Java NativeNfcTag object.
+ ** activationData: data from activation.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void fillNativeNfcTagMembers2 (JNIEnv* e, jclass tag_cls, jobject tag, tNFA_ACTIVATED& activationData);
+
+
+ /*******************************************************************************
+ **
+ ** Function: fillNativeNfcTagMembers3
+ **
+ ** Description: Fill NativeNfcTag's members: mTechPollBytes.
+ ** The original Google's implementation is in set_target_pollBytes(
+ ** in com_android_nfc_NativeNfcTag.cpp;
+ ** e: JVM environment.
+ ** tag_cls: Java NativeNfcTag class.
+ ** tag: Java NativeNfcTag object.
+ ** activationData: data from activation.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void fillNativeNfcTagMembers3 (JNIEnv* e, jclass tag_cls, jobject tag, tNFA_ACTIVATED& activationData);
+
+
+ /*******************************************************************************
+ **
+ ** Function: fillNativeNfcTagMembers4
+ **
+ ** Description: Fill NativeNfcTag's members: mTechActBytes.
+ ** The original Google's implementation is in set_target_activationBytes()
+ ** in com_android_nfc_NativeNfcTag.cpp;
+ ** e: JVM environment.
+ ** tag_cls: Java NativeNfcTag class.
+ ** tag: Java NativeNfcTag object.
+ ** activationData: data from activation.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void fillNativeNfcTagMembers4 (JNIEnv* e, jclass tag_cls, jobject tag, tNFA_ACTIVATED& activationData);
+
+
+ /*******************************************************************************
+ **
+ ** Function: fillNativeNfcTagMembers5
+ **
+ ** Description: Fill NativeNfcTag's members: mUid.
+ ** The original Google's implementation is in nfc_jni_Discovery_notification_callback()
+ ** in com_android_nfc_NativeNfcManager.cpp;
+ ** e: JVM environment.
+ ** tag_cls: Java NativeNfcTag class.
+ ** tag: Java NativeNfcTag object.
+ ** activationData: data from activation.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void fillNativeNfcTagMembers5 (JNIEnv* e, jclass tag_cls, jobject tag, tNFA_ACTIVATED& activationData);
+
+
+ /*******************************************************************************
+ **
+ ** Function: resetTechnologies
+ **
+ ** Description: Clear all data related to the technology, protocol of the tag.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void resetTechnologies ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: calculateT1tMaxMessageSize
+ **
+ ** Description: Calculate type-1 tag's max message size based on header ROM bytes.
+ ** activate: reference to activation data.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void calculateT1tMaxMessageSize (tNFA_ACTIVATED& activate);
+};
+
diff --git a/nci/jni/PeerToPeer.cpp b/nci/jni/PeerToPeer.cpp
new file mode 100644
index 0000000..7994e2a
--- /dev/null
+++ b/nci/jni/PeerToPeer.cpp
@@ -0,0 +1,1840 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+/*
+ * Communicate with a peer using NFC-DEP, LLCP, SNEP.
+ */
+#include "OverrideLog.h"
+#include "PeerToPeer.h"
+#include "NfcJniUtil.h"
+#include "llcp_defs.h"
+#include "config.h"
+#include "JavaClassConstants.h"
+
+using namespace android;
+
+namespace android
+{
+ extern void nativeNfcTag_registerNdefTypeHandler ();
+ extern void nativeNfcTag_deregisterNdefTypeHandler ();
+}
+
+
+PeerToPeer PeerToPeer::sP2p;
+const std::string P2pServer::sSnepServiceName ("urn:nfc:sn:snep");
+
+
+/*******************************************************************************
+**
+** Function: PeerToPeer
+**
+** Description: Initialize member variables.
+**
+** Returns: None
+**
+*******************************************************************************/
+PeerToPeer::PeerToPeer ()
+: mRemoteWKS (0),
+ mIsP2pListening (false),
+ mP2pListenTechMask (NFA_TECHNOLOGY_MASK_A
+ | NFA_TECHNOLOGY_MASK_F
+ | NFA_TECHNOLOGY_MASK_A_ACTIVE
+ | NFA_TECHNOLOGY_MASK_F_ACTIVE),
+ mNextJniHandle (1)
+{
+ unsigned long num = 0;
+ memset (mServers, 0, sizeof(mServers));
+ memset (mClients, 0, sizeof(mClients));
+}
+
+
+/*******************************************************************************
+**
+** Function: ~PeerToPeer
+**
+** Description: Free all resources.
+**
+** Returns: None
+**
+*******************************************************************************/
+PeerToPeer::~PeerToPeer ()
+{
+}
+
+
+/*******************************************************************************
+**
+** Function: getInstance
+**
+** Description: Get the singleton PeerToPeer object.
+**
+** Returns: Singleton PeerToPeer object.
+**
+*******************************************************************************/
+PeerToPeer& PeerToPeer::getInstance ()
+{
+ return sP2p;
+}
+
+
+/*******************************************************************************
+**
+** Function: initialize
+**
+** Description: Initialize member variables.
+**
+** Returns: None
+**
+*******************************************************************************/
+void PeerToPeer::initialize ()
+{
+ ALOGD ("PeerToPeer::initialize");
+ unsigned long num = 0;
+
+ if (GetNumValue ("P2P_LISTEN_TECH_MASK", &num, sizeof (num)))
+ mP2pListenTechMask = num;
+}
+
+
+/*******************************************************************************
+**
+** Function: findServerLocked
+**
+** Description: Find a PeerToPeer object by connection handle.
+** Assumes mMutex is already held
+** nfaP2pServerHandle: Connectin handle.
+**
+** Returns: PeerToPeer object.
+**
+*******************************************************************************/
+sp<P2pServer> PeerToPeer::findServerLocked (tNFA_HANDLE nfaP2pServerHandle)
+{
+ for (int i = 0; i < sMax; i++)
+ {
+ if ( (mServers[i] != NULL)
+ && (mServers[i]->mNfaP2pServerHandle == nfaP2pServerHandle) )
+ {
+ return (mServers [i]);
+ }
+ }
+
+ // If here, not found
+ return NULL;
+}
+
+
+/*******************************************************************************
+**
+** Function: findServerLocked
+**
+** Description: Find a PeerToPeer object by connection handle.
+** Assumes mMutex is already held
+** serviceName: service name.
+**
+** Returns: PeerToPeer object.
+**
+*******************************************************************************/
+sp<P2pServer> PeerToPeer::findServerLocked (tJNI_HANDLE jniHandle)
+{
+ for (int i = 0; i < sMax; i++)
+ {
+ if ( (mServers[i] != NULL)
+ && (mServers[i]->mJniHandle == jniHandle) )
+ {
+ return (mServers [i]);
+ }
+ }
+
+ // If here, not found
+ return NULL;
+}
+
+
+/*******************************************************************************
+**
+** Function: findServerLocked
+**
+** Description: Find a PeerToPeer object by service name
+** Assumes mMutex is already heldf
+** serviceName: service name.
+**
+** Returns: PeerToPeer object.
+**
+*******************************************************************************/
+sp<P2pServer> PeerToPeer::findServerLocked (const char *serviceName)
+{
+ for (int i = 0; i < sMax; i++)
+ {
+ if ( (mServers[i] != NULL) && (mServers[i]->mServiceName.compare(serviceName) == 0) )
+ return (mServers [i]);
+ }
+
+ // If here, not found
+ return NULL;
+}
+
+
+/*******************************************************************************
+**
+** Function: registerServer
+**
+** Description: Let a server start listening for peer's connection request.
+** jniHandle: Connection handle.
+** serviceName: Server's service name.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool PeerToPeer::registerServer (tJNI_HANDLE jniHandle, const char *serviceName)
+{
+ static const char fn [] = "PeerToPeer::registerServer";
+ ALOGD ("%s: enter; service name: %s JNI handle: %u", fn, serviceName, jniHandle);
+ tNFA_STATUS stat = NFA_STATUS_OK;
+ sp<P2pServer> pSrv = NULL;
+ UINT8 serverSap = NFA_P2P_ANY_SAP;
+
+ mMutex.lock();
+ // Check if already registered
+ if ((pSrv = findServerLocked(serviceName)) != NULL)
+ {
+ ALOGD ("%s: service name=%s already registered, handle: 0x%04x", fn, serviceName, pSrv->mNfaP2pServerHandle);
+
+ // Update JNI handle
+ pSrv->mJniHandle = jniHandle;
+ mMutex.unlock();
+ return (true);
+ }
+
+ for (int ii = 0; ii < sMax; ii++)
+ {
+ if (mServers[ii] == NULL)
+ {
+ pSrv = mServers[ii] = new P2pServer(jniHandle, serviceName);
+
+ ALOGD ("%s: added new p2p server index: %d handle: %u name: %s", fn, ii, jniHandle, serviceName);
+ break;
+ }
+ }
+ mMutex.unlock();
+
+ if (pSrv == NULL)
+ {
+ ALOGE ("%s: service name=%s no free entry", fn, serviceName);
+ return (false);
+ }
+
+ if (pSrv->registerWithStack()) {
+ ALOGD ("%s: got new p2p server h=0x%X", fn, pSrv->mNfaP2pServerHandle);
+ return (true);
+ } else {
+ ALOGE ("%s: invalid server handle", fn);
+ removeServer (jniHandle);
+ return (false);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: removeServer
+**
+** Description: Free resources related to a server.
+** jniHandle: Connection handle.
+**
+** Returns: None
+**
+*******************************************************************************/
+void PeerToPeer::removeServer (tJNI_HANDLE jniHandle)
+{
+ static const char fn [] = "PeerToPeer::removeServer";
+
+ AutoMutex mutex(mMutex);
+
+ for (int i = 0; i < sMax; i++)
+ {
+ if ( (mServers[i] != NULL) && (mServers[i]->mJniHandle == jniHandle) )
+ {
+ ALOGD ("%s: server jni_handle: %u; nfa_handle: 0x%04x; name: %s; index=%d",
+ fn, jniHandle, mServers[i]->mNfaP2pServerHandle, mServers[i]->mServiceName.c_str(), i);
+
+ mServers [i] = NULL;
+ return;
+ }
+ }
+ ALOGE ("%s: unknown server jni handle: %u", fn, jniHandle);
+}
+
+
+/*******************************************************************************
+**
+** Function: llcpActivatedHandler
+**
+** Description: Receive LLLCP-activated event from stack.
+** nat: JVM-related data.
+** activated: Event data.
+**
+** Returns: None
+**
+*******************************************************************************/
+void PeerToPeer::llcpActivatedHandler (nfc_jni_native_data* nat, tNFA_LLCP_ACTIVATED& activated)
+{
+ static const char fn [] = "PeerToPeer::llcpActivatedHandler";
+ ALOGD ("%s: enter", fn);
+ JNIEnv* e = NULL;
+ jclass tag_cls = NULL;
+ jobject tag = NULL;
+ jmethodID ctor = 0;
+ jfieldID f = 0;
+
+ //no longer need to receive NDEF message from a tag
+ android::nativeNfcTag_deregisterNdefTypeHandler ();
+
+ mRemoteWKS = activated.remote_wks;
+
+ nat->vm->AttachCurrentThread (&e, NULL);
+ if (e == NULL)
+ {
+ ALOGE ("%s: jni env is null", fn);
+ return;
+ }
+
+ ALOGD ("%s: get object class", fn);
+ tag_cls = e->GetObjectClass (nat->cached_P2pDevice);
+ if (e->ExceptionCheck())
+ {
+ e->ExceptionClear();
+ ALOGE ("%s: fail get p2p device", fn);
+ goto TheEnd;
+ }
+
+ ALOGD ("%s: instantiate", fn);
+ /* New target instance */
+ ctor = e->GetMethodID (tag_cls, "<init>", "()V");
+ tag = e->NewObject (tag_cls, ctor);
+
+ /* Set P2P Target mode */
+ f = e->GetFieldID (tag_cls, "mMode", "I");
+
+ if (activated.is_initiator == TRUE)
+ {
+ ALOGD ("%s: p2p initiator", fn);
+ e->SetIntField (tag, f, (jint) MODE_P2P_INITIATOR);
+ }
+ else
+ {
+ ALOGD ("%s: p2p target", fn);
+ e->SetIntField (tag, f, (jint) MODE_P2P_TARGET);
+ }
+
+ /* Set tag handle */
+ f = e->GetFieldID (tag_cls, "mHandle", "I");
+ e->SetIntField (tag, f, (jint) 0x1234); // ?? This handle is not used for anything
+
+ if (nat->tag != NULL)
+ {
+ e->DeleteGlobalRef (nat->tag);
+ }
+ nat->tag = e->NewGlobalRef (tag);
+
+ ALOGD ("%s: notify nfc service", fn);
+
+ /* Notify manager that new a P2P device was found */
+ e->CallVoidMethod (nat->manager, android::gCachedNfcManagerNotifyLlcpLinkActivation, tag);
+ if (e->ExceptionCheck())
+ {
+ e->ExceptionClear();
+ ALOGE ("%s: fail notify", fn);
+ }
+
+ e->DeleteLocalRef (tag);
+
+TheEnd:
+ nat->vm->DetachCurrentThread ();
+ ALOGD ("%s: exit", fn);
+}
+
+
+/*******************************************************************************
+**
+** Function: llcpDeactivatedHandler
+**
+** Description: Receive LLLCP-deactivated event from stack.
+** nat: JVM-related data.
+** deactivated: Event data.
+**
+** Returns: None
+**
+*******************************************************************************/
+void PeerToPeer::llcpDeactivatedHandler (nfc_jni_native_data* nat, tNFA_LLCP_DEACTIVATED& deactivated)
+{
+ static const char fn [] = "PeerToPeer::llcpDeactivatedHandler";
+ ALOGD ("%s: enter", fn);
+ JNIEnv* e = NULL;
+
+ nat->vm->AttachCurrentThread (&e, NULL);
+ if (e == NULL)
+ {
+ ALOGE ("%s: jni env is null", fn);
+ return;
+ }
+
+ ALOGD ("%s: notify nfc service", fn);
+ /* Notify manager that the LLCP is lost or deactivated */
+ e->CallVoidMethod (nat->manager, android::gCachedNfcManagerNotifyLlcpLinkDeactivated, nat->tag);
+ if (e->ExceptionCheck())
+ {
+ e->ExceptionClear();
+ ALOGE ("%s: fail notify", fn);
+ }
+
+ nat->vm->DetachCurrentThread ();
+
+ //let the tag-reading code handle NDEF data event
+ android::nativeNfcTag_registerNdefTypeHandler ();
+ ALOGD ("%s: exit", fn);
+}
+
+
+/*******************************************************************************
+**
+** Function: accept
+**
+** Description: Accept a peer's request to connect.
+** serverJniHandle: Server's handle.
+** connJniHandle: Connection handle.
+** maxInfoUnit: Maximum information unit.
+** recvWindow: Receive window size.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool PeerToPeer::accept (tJNI_HANDLE serverJniHandle, tJNI_HANDLE connJniHandle, int maxInfoUnit, int recvWindow)
+{
+ static const char fn [] = "PeerToPeer::accept";
+ tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
+ sp<NfaConn> *pConn = NULL;
+ bool stat = false;
+ int ii = 0;
+ sp<P2pServer> pSrv = NULL;
+
+ ALOGD ("%s: enter; server jni handle: %u; conn jni handle: %u; maxInfoUnit: %d; recvWindow: %d", fn,
+ serverJniHandle, connJniHandle, maxInfoUnit, recvWindow);
+
+ mMutex.lock();
+ if ((pSrv = findServerLocked (serverJniHandle)) == NULL)
+ {
+ ALOGE ("%s: unknown server jni handle: %u", fn, serverJniHandle);
+ mMutex.unlock();
+ return (false);
+ }
+ mMutex.unlock();
+
+ return pSrv->accept(serverJniHandle, connJniHandle, maxInfoUnit, recvWindow);
+}
+
+
+/*******************************************************************************
+**
+** Function: deregisterServer
+**
+** Description: Stop a P2pServer from listening for peer.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool PeerToPeer::deregisterServer (tJNI_HANDLE jniHandle)
+{
+ static const char fn [] = "PeerToPeer::deregisterServer";
+ ALOGD ("%s: enter; JNI handle: %u", fn, jniHandle);
+ tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
+ sp<P2pServer> pSrv = NULL;
+
+ mMutex.lock();
+ if ((pSrv = findServerLocked (jniHandle)) == NULL)
+ {
+ ALOGE ("%s: unknown service handle: %u", fn, jniHandle);
+ mMutex.unlock();
+ return (false);
+ }
+ mMutex.unlock();
+
+ {
+ // Server does not call NFA_P2pDisconnect(), so unblock the accept()
+ SyncEventGuard guard (pSrv->mConnRequestEvent);
+ pSrv->mConnRequestEvent.notifyOne();
+ }
+
+ nfaStat = NFA_P2pDeregister (pSrv->mNfaP2pServerHandle);
+ if (nfaStat != NFA_STATUS_OK)
+ {
+ ALOGE ("%s: deregister error=0x%X", fn, nfaStat);
+ }
+
+ removeServer (jniHandle);
+
+ ALOGD ("%s: exit", fn);
+ return true;
+}
+
+
+/*******************************************************************************
+**
+** Function: createClient
+**
+** Description: Create a P2pClient object for a new out-bound connection.
+** jniHandle: Connection handle.
+** miu: Maximum information unit.
+** rw: Receive window size.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool PeerToPeer::createClient (tJNI_HANDLE jniHandle, UINT16 miu, UINT8 rw)
+{
+ static const char fn [] = "PeerToPeer::createClient";
+ int i = 0;
+ ALOGD ("%s: enter: jni h: %u miu: %u rw: %u", fn, jniHandle, miu, rw);
+
+ mMutex.lock();
+ sp<P2pClient> client = NULL;
+ for (i = 0; i < sMax; i++)
+ {
+ if (mClients[i] == NULL)
+ {
+ mClients [i] = client = new P2pClient();
+
+ mClients [i]->mClientConn->mJniHandle = jniHandle;
+ mClients [i]->mClientConn->mMaxInfoUnit = miu;
+ mClients [i]->mClientConn->mRecvWindow = rw;
+ break;
+ }
+ }
+ mMutex.unlock();
+
+ if (client == NULL)
+ {
+ ALOGE ("%s: fail", fn);
+ return (false);
+ }
+
+ ALOGD ("%s: pClient: 0x%p assigned for client jniHandle: %u", fn, client.get(), jniHandle);
+
+ {
+ SyncEventGuard guard (mClients[i]->mRegisteringEvent);
+ NFA_P2pRegisterClient (NFA_P2P_DLINK_TYPE, nfaClientCallback);
+ mClients[i]->mRegisteringEvent.wait(); //wait for NFA_P2P_REG_CLIENT_EVT
+ }
+
+ if (mClients[i]->mNfaP2pClientHandle != NFA_HANDLE_INVALID)
+ {
+ ALOGD ("%s: exit; new client jniHandle: %u NFA Handle: 0x%04x", fn, jniHandle, client->mClientConn->mNfaConnHandle);
+ return (true);
+ }
+ else
+ {
+ ALOGE ("%s: FAILED; new client jniHandle: %u NFA Handle: 0x%04x", fn, jniHandle, client->mClientConn->mNfaConnHandle);
+ removeConn (jniHandle);
+ return (false);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: removeConn
+**
+** Description: Free resources related to a connection.
+** jniHandle: Connection handle.
+**
+** Returns: None
+**
+*******************************************************************************/
+void PeerToPeer::removeConn(tJNI_HANDLE jniHandle)
+{
+ static const char fn[] = "PeerToPeer::removeConn";
+ int ii = 0, jj = 0;
+
+ AutoMutex mutex(mMutex);
+ // If the connection is a for a client, delete the client itself
+ for (ii = 0; ii < sMax; ii++)
+ {
+ if ((mClients[ii] != NULL) && (mClients[ii]->mClientConn->mJniHandle == jniHandle))
+ {
+ if (mClients[ii]->mNfaP2pClientHandle != NFA_HANDLE_INVALID)
+ NFA_P2pDeregister (mClients[ii]->mNfaP2pClientHandle);
+
+ mClients[ii] = NULL;
+ ALOGD ("%s: deleted client handle: %u index: %u", fn, jniHandle, ii);
+ return;
+ }
+ }
+
+ // If the connection is for a server, just delete the connection
+ for (ii = 0; ii < sMax; ii++)
+ {
+ if (mServers[ii] != NULL)
+ {
+ if (mServers[ii]->removeServerConnection(jniHandle)) {
+ return;
+ }
+ }
+ }
+
+ ALOGE ("%s: could not find handle: %u", fn, jniHandle);
+}
+
+
+/*******************************************************************************
+**
+** Function: connectConnOriented
+**
+** Description: Estabish a connection-oriented connection to a peer.
+** jniHandle: Connection handle.
+** serviceName: Peer's service name.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool PeerToPeer::connectConnOriented (tJNI_HANDLE jniHandle, const char* serviceName)
+{
+ static const char fn [] = "PeerToPeer::connectConnOriented";
+ ALOGD ("%s: enter; h: %u service name=%s", fn, jniHandle, serviceName);
+ bool stat = createDataLinkConn (jniHandle, serviceName, 0);
+ ALOGD ("%s: exit; h: %u stat: %u", fn, jniHandle, stat);
+ return stat;
+}
+
+
+/*******************************************************************************
+**
+** Function: connectConnOriented
+**
+** Description: Estabish a connection-oriented connection to a peer.
+** jniHandle: Connection handle.
+** destinationSap: Peer's service access point.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool PeerToPeer::connectConnOriented (tJNI_HANDLE jniHandle, UINT8 destinationSap)
+{
+ static const char fn [] = "PeerToPeer::connectConnOriented";
+ ALOGD ("%s: enter; h: %u dest sap: 0x%X", fn, jniHandle, destinationSap);
+ bool stat = createDataLinkConn (jniHandle, NULL, destinationSap);
+ ALOGD ("%s: exit; h: %u stat: %u", fn, jniHandle, stat);
+ return stat;
+}
+
+
+/*******************************************************************************
+**
+** Function: createDataLinkConn
+**
+** Description: Estabish a connection-oriented connection to a peer.
+** jniHandle: Connection handle.
+** serviceName: Peer's service name.
+** destinationSap: Peer's service access point.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool PeerToPeer::createDataLinkConn (tJNI_HANDLE jniHandle, const char* serviceName, UINT8 destinationSap)
+{
+ static const char fn [] = "PeerToPeer::createDataLinkConn";
+ ALOGD ("%s: enter", fn);
+ tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
+ sp<P2pClient> pClient = NULL;
+
+ if ((pClient = findClient (jniHandle)) == NULL)
+ {
+ ALOGE ("%s: can't find client, JNI handle: %u", fn, jniHandle);
+ return (false);
+ }
+
+ {
+ SyncEventGuard guard (pClient->mConnectingEvent);
+ pClient->mIsConnecting = true;
+
+ if (serviceName)
+ nfaStat = NFA_P2pConnectByName (pClient->mNfaP2pClientHandle,
+ const_cast<char*>(serviceName), pClient->mClientConn->mMaxInfoUnit,
+ pClient->mClientConn->mRecvWindow);
+ else if (destinationSap)
+ nfaStat = NFA_P2pConnectBySap (pClient->mNfaP2pClientHandle, destinationSap,
+ pClient->mClientConn->mMaxInfoUnit, pClient->mClientConn->mRecvWindow);
+ if (nfaStat == NFA_STATUS_OK)
+ {
+ ALOGD ("%s: wait for connected event mConnectingEvent: 0x%p", fn, pClient.get());
+ pClient->mConnectingEvent.wait();
+ }
+ }
+
+ if (nfaStat == NFA_STATUS_OK)
+ {
+ if (pClient->mClientConn->mNfaConnHandle == NFA_HANDLE_INVALID)
+ {
+ removeConn (jniHandle);
+ nfaStat = NFA_STATUS_FAILED;
+ }
+ else
+ pClient->mIsConnecting = false;
+ }
+ else
+ {
+ removeConn (jniHandle);
+ ALOGE ("%s: fail; error=0x%X", fn, nfaStat);
+ }
+
+ ALOGD ("%s: exit", fn);
+ return nfaStat == NFA_STATUS_OK;
+}
+
+
+/*******************************************************************************
+**
+** Function: findClient
+**
+** Description: Find a PeerToPeer object with a client connection handle.
+** nfaConnHandle: Connection handle.
+**
+** Returns: PeerToPeer object.
+**
+*******************************************************************************/
+sp<P2pClient> PeerToPeer::findClient (tNFA_HANDLE nfaConnHandle)
+{
+ AutoMutex mutex(mMutex);
+ for (int i = 0; i < sMax; i++)
+ {
+ if ((mClients[i] != NULL) && (mClients[i]->mNfaP2pClientHandle == nfaConnHandle))
+ return (mClients[i]);
+ }
+ return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function: findClient
+**
+** Description: Find a PeerToPeer object with a client connection handle.
+** jniHandle: Connection handle.
+**
+** Returns: PeerToPeer object.
+**
+*******************************************************************************/
+sp<P2pClient> PeerToPeer::findClient (tJNI_HANDLE jniHandle)
+{
+ AutoMutex mutex(mMutex);
+ for (int i = 0; i < sMax; i++)
+ {
+ if ((mClients[i] != NULL) && (mClients[i]->mClientConn->mJniHandle == jniHandle))
+ return (mClients[i]);
+ }
+ return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function: findClientCon
+**
+** Description: Find a PeerToPeer object with a client connection handle.
+** nfaConnHandle: Connection handle.
+**
+** Returns: PeerToPeer object.
+**
+*******************************************************************************/
+sp<P2pClient> PeerToPeer::findClientCon (tNFA_HANDLE nfaConnHandle)
+{
+ AutoMutex mutex(mMutex);
+ for (int i = 0; i < sMax; i++)
+ {
+ if ((mClients[i] != NULL) && (mClients[i]->mClientConn->mNfaConnHandle == nfaConnHandle))
+ return (mClients[i]);
+ }
+ return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function: findConnection
+**
+** Description: Find a PeerToPeer object with a connection handle.
+** nfaConnHandle: Connection handle.
+**
+** Returns: PeerToPeer object.
+**
+*******************************************************************************/
+sp<NfaConn> PeerToPeer::findConnection (tNFA_HANDLE nfaConnHandle)
+{
+ int ii = 0, jj = 0;
+
+ AutoMutex mutex(mMutex);
+ // First, look through all the client control blocks
+ for (ii = 0; ii < sMax; ii++)
+ {
+ if ( (mClients[ii] != NULL)
+ && (mClients[ii]->mClientConn->mNfaConnHandle == nfaConnHandle) ) {
+ return mClients[ii]->mClientConn;
+ }
+ }
+
+ // Not found yet. Look through all the server control blocks
+ for (ii = 0; ii < sMax; ii++)
+ {
+ if (mServers[ii] != NULL)
+ {
+ sp<NfaConn> conn = mServers[ii]->findServerConnection(nfaConnHandle);
+ if (conn != NULL) {
+ return conn;
+ }
+ }
+ }
+
+ // Not found...
+ return NULL;
+}
+
+
+/*******************************************************************************
+**
+** Function: findConnection
+**
+** Description: Find a PeerToPeer object with a connection handle.
+** jniHandle: Connection handle.
+**
+** Returns: PeerToPeer object.
+**
+*******************************************************************************/
+sp<NfaConn> PeerToPeer::findConnection (tJNI_HANDLE jniHandle)
+{
+ int ii = 0, jj = 0;
+
+ AutoMutex mutex(mMutex);
+ // First, look through all the client control blocks
+ for (ii = 0; ii < sMax; ii++)
+ {
+ if ( (mClients[ii] != NULL)
+ && (mClients[ii]->mClientConn->mJniHandle == jniHandle) ) {
+ return mClients[ii]->mClientConn;
+ }
+ }
+
+ // Not found yet. Look through all the server control blocks
+ for (ii = 0; ii < sMax; ii++)
+ {
+ if (mServers[ii] != NULL)
+ {
+ sp<NfaConn> conn = mServers[ii]->findServerConnection(jniHandle);
+ if (conn != NULL) {
+ return conn;
+ }
+ }
+ }
+
+ // Not found...
+ return NULL;
+}
+
+
+/*******************************************************************************
+**
+** Function: send
+**
+** Description: Send data to peer.
+** jniHandle: Handle of connection.
+** buffer: Buffer of data.
+** bufferLen: Length of data.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool PeerToPeer::send (tJNI_HANDLE jniHandle, UINT8 *buffer, UINT16 bufferLen)
+{
+ static const char fn [] = "PeerToPeer::send";
+ tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
+ sp<NfaConn> pConn = NULL;
+
+ if ((pConn = findConnection (jniHandle)) == NULL)
+ {
+ ALOGE ("%s: can't find connection handle: %u", fn, jniHandle);
+ return (false);
+ }
+
+ ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: send data; jniHandle: %u nfaHandle: 0x%04X",
+ fn, pConn->mJniHandle, pConn->mNfaConnHandle);
+
+ while (true)
+ {
+ SyncEventGuard guard (pConn->mCongEvent);
+ nfaStat = NFA_P2pSendData (pConn->mNfaConnHandle, bufferLen, buffer);
+ if (nfaStat == NFA_STATUS_CONGESTED)
+ pConn->mCongEvent.wait (); //wait for NFA_P2P_CONGEST_EVT
+ else
+ break;
+
+ if (pConn->mNfaConnHandle == NFA_HANDLE_INVALID) //peer already disconnected
+ {
+ ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: peer disconnected", fn);
+ return (false);
+ }
+ }
+
+ if (nfaStat == NFA_STATUS_OK)
+ ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: exit OK; JNI handle: %u NFA Handle: 0x%04x", fn, jniHandle, pConn->mNfaConnHandle);
+ else
+ ALOGE ("%s: Data not sent; JNI handle: %u NFA Handle: 0x%04x error: 0x%04x",
+ fn, jniHandle, pConn->mNfaConnHandle, nfaStat);
+
+ return nfaStat == NFA_STATUS_OK;
+}
+
+
+/*******************************************************************************
+**
+** Function: receive
+**
+** Description: Receive data from peer.
+** jniHandle: Handle of connection.
+** buffer: Buffer to store data.
+** bufferLen: Max length of buffer.
+** actualLen: Actual length received.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool PeerToPeer::receive (tJNI_HANDLE jniHandle, UINT8* buffer, UINT16 bufferLen, UINT16& actualLen)
+{
+ static const char fn [] = "PeerToPeer::receive";
+ ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: enter; jniHandle: %u bufferLen: %u", fn, jniHandle, bufferLen);
+ sp<NfaConn> pConn = NULL;
+ tNFA_STATUS stat = NFA_STATUS_FAILED;
+ UINT32 actualDataLen2 = 0;
+ BOOLEAN isMoreData = TRUE;
+ bool retVal = false;
+
+ if ((pConn = findConnection (jniHandle)) == NULL)
+ {
+ ALOGE ("%s: can't find connection handle: %u", fn, jniHandle);
+ return (false);
+ }
+
+ ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: jniHandle: %u nfaHandle: 0x%04X buf len=%u", fn, pConn->mJniHandle, pConn->mNfaConnHandle, bufferLen);
+
+ while (pConn->mNfaConnHandle != NFA_HANDLE_INVALID)
+ {
+ //NFA_P2pReadData() is synchronous
+ stat = NFA_P2pReadData (pConn->mNfaConnHandle, bufferLen, &actualDataLen2, buffer, &isMoreData);
+ if ((stat == NFA_STATUS_OK) && (actualDataLen2 > 0)) //received some data
+ {
+ actualLen = (UINT16) actualDataLen2;
+ retVal = true;
+ break;
+ }
+ ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: waiting for data...", fn);
+ {
+ SyncEventGuard guard (pConn->mReadEvent);
+ pConn->mReadEvent.wait();
+ }
+ } //while
+
+ ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: exit; nfa h: 0x%X ok: %u actual len: %u", fn, pConn->mNfaConnHandle, retVal, actualLen);
+ return retVal;
+}
+
+
+/*******************************************************************************
+**
+** Function: disconnectConnOriented
+**
+** Description: Disconnect a connection-oriented connection with peer.
+** jniHandle: Handle of connection.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool PeerToPeer::disconnectConnOriented (tJNI_HANDLE jniHandle)
+{
+ static const char fn [] = "PeerToPeer::disconnectConnOriented";
+ tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
+ sp<P2pClient> pClient = NULL;
+ sp<NfaConn> pConn = NULL;
+
+ ALOGD ("%s: enter; jni handle: %u", fn, jniHandle);
+
+ if ((pConn = findConnection(jniHandle)) == NULL)
+ {
+ ALOGE ("%s: can't find connection handle: %u", fn, jniHandle);
+ return (false);
+ }
+
+ // If this is a client, he may not be connected yet, so unblock him just in case
+ if ( ((pClient = findClient(jniHandle)) != NULL) && (pClient->mIsConnecting) )
+ {
+ SyncEventGuard guard (pClient->mConnectingEvent);
+ pClient->mConnectingEvent.notifyOne();
+ return (true);
+ }
+
+ {
+ SyncEventGuard guard1 (pConn->mCongEvent);
+ pConn->mCongEvent.notifyOne (); //unblock send() if congested
+ }
+ {
+ SyncEventGuard guard2 (pConn->mReadEvent);
+ pConn->mReadEvent.notifyOne (); //unblock receive()
+ }
+
+ if (pConn->mNfaConnHandle != NFA_HANDLE_INVALID)
+ {
+ ALOGD ("%s: try disconn nfa h=0x%04X", fn, pConn->mNfaConnHandle);
+ SyncEventGuard guard (pConn->mDisconnectingEvent);
+ nfaStat = NFA_P2pDisconnect (pConn->mNfaConnHandle, FALSE);
+
+ if (nfaStat != NFA_STATUS_OK)
+ ALOGE ("%s: fail p2p disconnect", fn);
+ else
+ pConn->mDisconnectingEvent.wait();
+ }
+
+ mDisconnectMutex.lock ();
+ removeConn (jniHandle);
+ mDisconnectMutex.unlock ();
+
+ ALOGD ("%s: exit; jni handle: %u", fn, jniHandle);
+ return nfaStat == NFA_STATUS_OK;
+}
+
+
+/*******************************************************************************
+**
+** Function: getRemoteMaxInfoUnit
+**
+** Description: Get peer's max information unit.
+** jniHandle: Handle of the connection.
+**
+** Returns: Peer's max information unit.
+**
+*******************************************************************************/
+UINT16 PeerToPeer::getRemoteMaxInfoUnit (tJNI_HANDLE jniHandle)
+{
+ static const char fn [] = "PeerToPeer::getRemoteMaxInfoUnit";
+ sp<NfaConn> pConn = NULL;
+
+ if ((pConn = findConnection(jniHandle)) == NULL)
+ {
+ ALOGE ("%s: can't find client jniHandle: %u", fn, jniHandle);
+ return 0;
+ }
+ ALOGD ("%s: jniHandle: %u MIU: %u", fn, jniHandle, pConn->mRemoteMaxInfoUnit);
+ return (pConn->mRemoteMaxInfoUnit);
+}
+
+
+/*******************************************************************************
+**
+** Function: getRemoteRecvWindow
+**
+** Description: Get peer's receive window size.
+** jniHandle: Handle of the connection.
+**
+** Returns: Peer's receive window size.
+**
+*******************************************************************************/
+UINT8 PeerToPeer::getRemoteRecvWindow (tJNI_HANDLE jniHandle)
+{
+ static const char fn [] = "PeerToPeer::getRemoteRecvWindow";
+ ALOGD ("%s: client jni handle: %u", fn, jniHandle);
+ sp<NfaConn> pConn = NULL;
+
+ if ((pConn = findConnection(jniHandle)) == NULL)
+ {
+ ALOGE ("%s: can't find client", fn);
+ return 0;
+ }
+ return pConn->mRemoteRecvWindow;
+}
+
+/*******************************************************************************
+**
+** Function: setP2pListenMask
+**
+** Description: Sets the p2p listen technology mask.
+** p2pListenMask: the p2p listen mask to be set?
+**
+** Returns: None
+**
+*******************************************************************************/
+void PeerToPeer::setP2pListenMask (tNFA_TECHNOLOGY_MASK p2pListenMask) {
+ mP2pListenTechMask = p2pListenMask;
+}
+
+/*******************************************************************************
+**
+** Function: enableP2pListening
+**
+** Description: Start/stop polling/listening to peer that supports P2P.
+** isEnable: Is enable polling/listening?
+**
+** Returns: None
+**
+*******************************************************************************/
+void PeerToPeer::enableP2pListening (bool isEnable)
+{
+ static const char fn [] = "PeerToPeer::enableP2pListening";
+ tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
+
+ ALOGD ("%s: enter isEnable: %u mIsP2pListening: %u", fn, isEnable, mIsP2pListening);
+
+ // If request to enable P2P listening, and we were not already listening
+ if ( (isEnable == true) && (mIsP2pListening == false) && (mP2pListenTechMask != 0) )
+ {
+ SyncEventGuard guard (mSetTechEvent);
+ if ((nfaStat = NFA_SetP2pListenTech (mP2pListenTechMask)) == NFA_STATUS_OK)
+ {
+ mSetTechEvent.wait ();
+ mIsP2pListening = true;
+ }
+ else
+ ALOGE ("%s: fail enable listen; error=0x%X", fn, nfaStat);
+ }
+ else if ( (isEnable == false) && (mIsP2pListening == true) )
+ {
+ SyncEventGuard guard (mSetTechEvent);
+ // Request to disable P2P listening, check if it was enabled
+ if ((nfaStat = NFA_SetP2pListenTech(0)) == NFA_STATUS_OK)
+ {
+ mSetTechEvent.wait ();
+ mIsP2pListening = false;
+ }
+ else
+ ALOGE ("%s: fail disable listen; error=0x%X", fn, nfaStat);
+ }
+ ALOGD ("%s: exit; mIsP2pListening: %u", fn, mIsP2pListening);
+}
+
+
+/*******************************************************************************
+**
+** Function: handleNfcOnOff
+**
+** Description: Handle events related to turning NFC on/off by the user.
+** isOn: Is NFC turning on?
+**
+** Returns: None
+**
+*******************************************************************************/
+void PeerToPeer::handleNfcOnOff (bool isOn)
+{
+ static const char fn [] = "PeerToPeer::handleNfcOnOff";
+ ALOGD ("%s: enter; is on=%u", fn, isOn);
+ tNFA_STATUS stat = NFA_STATUS_FAILED;
+
+ mIsP2pListening = false; // In both cases, P2P will not be listening
+
+ AutoMutex mutex(mMutex);
+ if (isOn)
+ {
+ // Start with no clients or servers
+ memset (mServers, 0, sizeof(mServers));
+ memset (mClients, 0, sizeof(mClients));
+ }
+ else
+ {
+ int ii = 0, jj = 0;
+
+ // Disconnect through all the clients
+ for (ii = 0; ii < sMax; ii++)
+ {
+ if (mClients[ii] != NULL)
+ {
+ if (mClients[ii]->mClientConn->mNfaConnHandle == NFA_HANDLE_INVALID)
+ {
+ SyncEventGuard guard (mClients[ii]->mConnectingEvent);
+ mClients[ii]->mConnectingEvent.notifyOne();
+ }
+ else
+ {
+ mClients[ii]->mClientConn->mNfaConnHandle = NFA_HANDLE_INVALID;
+ {
+ SyncEventGuard guard1 (mClients[ii]->mClientConn->mCongEvent);
+ mClients[ii]->mClientConn->mCongEvent.notifyOne (); //unblock send()
+ }
+ {
+ SyncEventGuard guard2 (mClients[ii]->mClientConn->mReadEvent);
+ mClients[ii]->mClientConn->mReadEvent.notifyOne (); //unblock receive()
+ }
+ }
+ }
+ } //loop
+
+ // Now look through all the server control blocks
+ for (ii = 0; ii < sMax; ii++)
+ {
+ if (mServers[ii] != NULL)
+ {
+ mServers[ii]->unblockAll();
+ }
+ } //loop
+
+ }
+ ALOGD ("%s: exit", fn);
+}
+
+
+/*******************************************************************************
+**
+** Function: nfaServerCallback
+**
+** Description: Receive LLCP-related events from the stack.
+** p2pEvent: Event code.
+** eventData: Event data.
+**
+** Returns: None
+**
+*******************************************************************************/
+void PeerToPeer::nfaServerCallback (tNFA_P2P_EVT p2pEvent, tNFA_P2P_EVT_DATA* eventData)
+{
+ static const char fn [] = "PeerToPeer::nfaServerCallback";
+ sp<P2pServer> pSrv = NULL;
+ sp<NfaConn> pConn = NULL;
+
+ ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: enter; event=0x%X", fn, p2pEvent);
+
+ switch (p2pEvent)
+ {
+ case NFA_P2P_REG_SERVER_EVT: // NFA_P2pRegisterServer() has started to listen
+ ALOGD ("%s: NFA_P2P_REG_SERVER_EVT; handle: 0x%04x; service sap=0x%02x name: %s", fn,
+ eventData->reg_server.server_handle, eventData->reg_server.server_sap, eventData->reg_server.service_name);
+
+ sP2p.mMutex.lock();
+ pSrv = sP2p.findServerLocked(eventData->reg_server.service_name);
+ sP2p.mMutex.unlock();
+ if (pSrv == NULL)
+ {
+ ALOGE ("%s: NFA_P2P_REG_SERVER_EVT for unknown service: %s", fn, eventData->reg_server.service_name);
+ }
+ else
+ {
+ SyncEventGuard guard (pSrv->mRegServerEvent);
+ pSrv->mNfaP2pServerHandle = eventData->reg_server.server_handle;
+ pSrv->mRegServerEvent.notifyOne(); //unblock registerServer()
+ }
+ break;
+
+ case NFA_P2P_ACTIVATED_EVT: //remote device has activated
+ ALOGD ("%s: NFA_P2P_ACTIVATED_EVT; handle: 0x%04x", fn, eventData->activated.handle);
+ break;
+
+ case NFA_P2P_DEACTIVATED_EVT:
+ ALOGD ("%s: NFA_P2P_DEACTIVATED_EVT; handle: 0x%04x", fn, eventData->activated.handle);
+ break;
+
+ case NFA_P2P_CONN_REQ_EVT:
+ ALOGD ("%s: NFA_P2P_CONN_REQ_EVT; nfa server h=0x%04x; nfa conn h=0x%04x; remote sap=0x%02x", fn,
+ eventData->conn_req.server_handle, eventData->conn_req.conn_handle, eventData->conn_req.remote_sap);
+
+ sP2p.mMutex.lock();
+ pSrv = sP2p.findServerLocked(eventData->conn_req.server_handle);
+ sP2p.mMutex.unlock();
+ if (pSrv == NULL)
+ {
+ ALOGE ("%s: NFA_P2P_CONN_REQ_EVT; unknown server h", fn);
+ return;
+ }
+ ALOGD ("%s: NFA_P2P_CONN_REQ_EVT; server jni h=%u", fn, pSrv->mJniHandle);
+
+ // Look for a connection block that is waiting (handle invalid)
+ if ((pConn = pSrv->findServerConnection((tNFA_HANDLE) NFA_HANDLE_INVALID)) == NULL)
+ {
+ ALOGE ("%s: NFA_P2P_CONN_REQ_EVT; server not listening", fn);
+ }
+ else
+ {
+ SyncEventGuard guard (pSrv->mConnRequestEvent);
+ pConn->mNfaConnHandle = eventData->conn_req.conn_handle;
+ pConn->mRemoteMaxInfoUnit = eventData->conn_req.remote_miu;
+ pConn->mRemoteRecvWindow = eventData->conn_req.remote_rw;
+ ALOGD ("%s: NFA_P2P_CONN_REQ_EVT; server jni h=%u; conn jni h=%u; notify conn req", fn, pSrv->mJniHandle, pConn->mJniHandle);
+ pSrv->mConnRequestEvent.notifyOne(); //unblock accept()
+ }
+ break;
+
+ case NFA_P2P_CONNECTED_EVT:
+ ALOGD ("%s: NFA_P2P_CONNECTED_EVT; h=0x%x remote sap=0x%X", fn,
+ eventData->connected.client_handle, eventData->connected.remote_sap);
+ break;
+
+ case NFA_P2P_DISC_EVT:
+ ALOGD ("%s: NFA_P2P_DISC_EVT; h=0x%04x; reason=0x%X", fn, eventData->disc.handle, eventData->disc.reason);
+ // Look for the connection block
+ if ((pConn = sP2p.findConnection(eventData->disc.handle)) == NULL)
+ {
+ ALOGE ("%s: NFA_P2P_DISC_EVT: can't find conn for NFA handle: 0x%04x", fn, eventData->disc.handle);
+ }
+ else
+ {
+ sP2p.mDisconnectMutex.lock ();
+ pConn->mNfaConnHandle = NFA_HANDLE_INVALID;
+ {
+ ALOGD ("%s: NFA_P2P_DISC_EVT; try guard disconn event", fn);
+ SyncEventGuard guard3 (pConn->mDisconnectingEvent);
+ pConn->mDisconnectingEvent.notifyOne ();
+ ALOGD ("%s: NFA_P2P_DISC_EVT; notified disconn event", fn);
+ }
+ {
+ ALOGD ("%s: NFA_P2P_DISC_EVT; try guard congest event", fn);
+ SyncEventGuard guard1 (pConn->mCongEvent);
+ pConn->mCongEvent.notifyOne (); //unblock write (if congested)
+ ALOGD ("%s: NFA_P2P_DISC_EVT; notified congest event", fn);
+ }
+ {
+ ALOGD ("%s: NFA_P2P_DISC_EVT; try guard read event", fn);
+ SyncEventGuard guard2 (pConn->mReadEvent);
+ pConn->mReadEvent.notifyOne (); //unblock receive()
+ ALOGD ("%s: NFA_P2P_DISC_EVT; notified read event", fn);
+ }
+ sP2p.mDisconnectMutex.unlock ();
+ }
+ break;
+
+ case NFA_P2P_DATA_EVT:
+ // Look for the connection block
+ if ((pConn = sP2p.findConnection(eventData->data.handle)) == NULL)
+ {
+ ALOGE ("%s: NFA_P2P_DATA_EVT: can't find conn for NFA handle: 0x%04x", fn, eventData->data.handle);
+ }
+ else
+ {
+ ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: NFA_P2P_DATA_EVT; h=0x%X; remote sap=0x%X", fn,
+ eventData->data.handle, eventData->data.remote_sap);
+ SyncEventGuard guard (pConn->mReadEvent);
+ pConn->mReadEvent.notifyOne();
+ }
+ break;
+
+ case NFA_P2P_CONGEST_EVT:
+ // Look for the connection block
+ if ((pConn = sP2p.findConnection(eventData->congest.handle)) == NULL)
+ {
+ ALOGE ("%s: NFA_P2P_CONGEST_EVT: can't find conn for NFA handle: 0x%04x", fn, eventData->congest.handle);
+ }
+ else
+ {
+ ALOGD ("%s: NFA_P2P_CONGEST_EVT; nfa handle: 0x%04x congested: %u", fn,
+ eventData->congest.handle, eventData->congest.is_congested);
+ if (eventData->congest.is_congested == FALSE)
+ {
+ SyncEventGuard guard (pConn->mCongEvent);
+ pConn->mCongEvent.notifyOne();
+ }
+ }
+ break;
+
+ default:
+ ALOGE ("%s: unknown event 0x%X ????", fn, p2pEvent);
+ break;
+ }
+ ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: exit", fn);
+}
+
+
+/*******************************************************************************
+**
+** Function: nfaClientCallback
+**
+** Description: Receive LLCP-related events from the stack.
+** p2pEvent: Event code.
+** eventData: Event data.
+**
+** Returns: None
+**
+*******************************************************************************/
+void PeerToPeer::nfaClientCallback (tNFA_P2P_EVT p2pEvent, tNFA_P2P_EVT_DATA* eventData)
+{
+ static const char fn [] = "PeerToPeer::nfaClientCallback";
+ sp<NfaConn> pConn = NULL;
+ sp<P2pClient> pClient = NULL;
+
+ ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: enter; event=%u", fn, p2pEvent);
+
+ switch (p2pEvent)
+ {
+ case NFA_P2P_REG_CLIENT_EVT:
+ // Look for a client that is trying to register
+ if ((pClient = sP2p.findClient ((tNFA_HANDLE)NFA_HANDLE_INVALID)) == NULL)
+ {
+ ALOGE ("%s: NFA_P2P_REG_CLIENT_EVT: can't find waiting client", fn);
+ }
+ else
+ {
+ ALOGD ("%s: NFA_P2P_REG_CLIENT_EVT; Conn Handle: 0x%04x, pClient: 0x%p", fn, eventData->reg_client.client_handle, pClient.get());
+
+ SyncEventGuard guard (pClient->mRegisteringEvent);
+ pClient->mNfaP2pClientHandle = eventData->reg_client.client_handle;
+ pClient->mRegisteringEvent.notifyOne();
+ }
+ break;
+
+ case NFA_P2P_ACTIVATED_EVT:
+ // Look for a client that is trying to register
+ if ((pClient = sP2p.findClient (eventData->activated.handle)) == NULL)
+ {
+ ALOGE ("%s: NFA_P2P_ACTIVATED_EVT: can't find client", fn);
+ }
+ else
+ {
+ ALOGD ("%s: NFA_P2P_ACTIVATED_EVT; Conn Handle: 0x%04x, pClient: 0x%p", fn, eventData->activated.handle, pClient.get());
+ }
+ break;
+
+ case NFA_P2P_DEACTIVATED_EVT:
+ ALOGD ("%s: NFA_P2P_DEACTIVATED_EVT: conn handle: 0x%X", fn, eventData->deactivated.handle);
+ break;
+
+ case NFA_P2P_CONNECTED_EVT:
+ // Look for the client that is trying to connect
+ if ((pClient = sP2p.findClient (eventData->connected.client_handle)) == NULL)
+ {
+ ALOGE ("%s: NFA_P2P_CONNECTED_EVT: can't find client: 0x%04x", fn, eventData->connected.client_handle);
+ }
+ else
+ {
+ ALOGD ("%s: NFA_P2P_CONNECTED_EVT; client_handle=0x%04x conn_handle: 0x%04x remote sap=0x%X pClient: 0x%p", fn,
+ eventData->connected.client_handle, eventData->connected.conn_handle, eventData->connected.remote_sap, pClient.get());
+
+ SyncEventGuard guard (pClient->mConnectingEvent);
+ pClient->mClientConn->mNfaConnHandle = eventData->connected.conn_handle;
+ pClient->mClientConn->mRemoteMaxInfoUnit = eventData->connected.remote_miu;
+ pClient->mClientConn->mRemoteRecvWindow = eventData->connected.remote_rw;
+ pClient->mConnectingEvent.notifyOne(); //unblock createDataLinkConn()
+ }
+ break;
+
+ case NFA_P2P_DISC_EVT:
+ ALOGD ("%s: NFA_P2P_DISC_EVT; h=0x%04x; reason=0x%X", fn, eventData->disc.handle, eventData->disc.reason);
+ // Look for the connection block
+ if ((pConn = sP2p.findConnection(eventData->disc.handle)) == NULL)
+ {
+ // If no connection, may be a client that is trying to connect
+ if ((pClient = sP2p.findClientCon ((tNFA_HANDLE)NFA_HANDLE_INVALID)) == NULL)
+ {
+ ALOGE ("%s: NFA_P2P_DISC_EVT: can't find conn for NFA handle: 0x%04x", fn, eventData->disc.handle);
+ return;
+ }
+ // Unblock createDataLinkConn()
+ SyncEventGuard guard (pClient->mConnectingEvent);
+ pClient->mConnectingEvent.notifyOne();
+ }
+ else
+ {
+ sP2p.mDisconnectMutex.lock ();
+ pConn->mNfaConnHandle = NFA_HANDLE_INVALID;
+ {
+ ALOGD ("%s: NFA_P2P_DISC_EVT; try guard disconn event", fn);
+ SyncEventGuard guard3 (pConn->mDisconnectingEvent);
+ pConn->mDisconnectingEvent.notifyOne ();
+ ALOGD ("%s: NFA_P2P_DISC_EVT; notified disconn event", fn);
+ }
+ {
+ ALOGD ("%s: NFA_P2P_DISC_EVT; try guard congest event", fn);
+ SyncEventGuard guard1 (pConn->mCongEvent);
+ pConn->mCongEvent.notifyOne(); //unblock write (if congested)
+ ALOGD ("%s: NFA_P2P_DISC_EVT; notified congest event", fn);
+ }
+ {
+ ALOGD ("%s: NFA_P2P_DISC_EVT; try guard read event", fn);
+ SyncEventGuard guard2 (pConn->mReadEvent);
+ pConn->mReadEvent.notifyOne(); //unblock receive()
+ ALOGD ("%s: NFA_P2P_DISC_EVT; notified read event", fn);
+ }
+ sP2p.mDisconnectMutex.unlock ();
+ }
+ break;
+
+ case NFA_P2P_DATA_EVT:
+ // Look for the connection block
+ if ((pConn = sP2p.findConnection(eventData->data.handle)) == NULL)
+ {
+ ALOGE ("%s: NFA_P2P_DATA_EVT: can't find conn for NFA handle: 0x%04x", fn, eventData->data.handle);
+ }
+ else
+ {
+ ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: NFA_P2P_DATA_EVT; h=0x%X; remote sap=0x%X", fn,
+ eventData->data.handle, eventData->data.remote_sap);
+ SyncEventGuard guard (pConn->mReadEvent);
+ pConn->mReadEvent.notifyOne();
+ }
+ break;
+
+ case NFA_P2P_CONGEST_EVT:
+ // Look for the connection block
+ if ((pConn = sP2p.findConnection(eventData->congest.handle)) == NULL)
+ {
+ ALOGE ("%s: NFA_P2P_CONGEST_EVT: can't find conn for NFA handle: 0x%04x", fn, eventData->congest.handle);
+ }
+ else
+ {
+ ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: NFA_P2P_CONGEST_EVT; nfa handle: 0x%04x congested: %u", fn,
+ eventData->congest.handle, eventData->congest.is_congested);
+
+ SyncEventGuard guard (pConn->mCongEvent);
+ pConn->mCongEvent.notifyOne();
+ }
+ break;
+
+ default:
+ ALOGE ("%s: unknown event 0x%X ????", fn, p2pEvent);
+ break;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: connectionEventHandler
+**
+** Description: Receive events from the stack.
+** event: Event code.
+** eventData: Event data.
+**
+** Returns: None
+**
+*******************************************************************************/
+void PeerToPeer::connectionEventHandler (UINT8 event, tNFA_CONN_EVT_DATA* eventData)
+{
+ switch (event)
+ {
+ case NFA_SET_P2P_LISTEN_TECH_EVT:
+ {
+ SyncEventGuard guard (mSetTechEvent);
+ mSetTechEvent.notifyOne(); //unblock NFA_SetP2pListenTech()
+ break;
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: getNextJniHandle
+**
+** Description: Get a new JNI handle.
+**
+** Returns: A new JNI handle.
+**
+*******************************************************************************/
+PeerToPeer::tJNI_HANDLE PeerToPeer::getNewJniHandle ()
+{
+ tJNI_HANDLE newHandle = 0;
+
+ mNewJniHandleMutex.lock ();
+ newHandle = mNextJniHandle++;
+ mNewJniHandleMutex.unlock ();
+ return newHandle;
+}
+
+
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+
+
+/*******************************************************************************
+**
+** Function: P2pServer
+**
+** Description: Initialize member variables.
+**
+** Returns: None
+**
+*******************************************************************************/
+P2pServer::P2pServer(PeerToPeer::tJNI_HANDLE jniHandle, const char* serviceName)
+: mNfaP2pServerHandle (NFA_HANDLE_INVALID),
+ mJniHandle (jniHandle)
+{
+ mServiceName.assign (serviceName);
+
+ memset (mServerConn, 0, sizeof(mServerConn));
+}
+
+bool P2pServer::registerWithStack()
+{
+ static const char fn [] = "P2pServer::registerWithStack";
+ ALOGD ("%s: enter; service name: %s JNI handle: %u", fn, mServiceName.c_str(), mJniHandle);
+ tNFA_STATUS stat = NFA_STATUS_OK;
+ UINT8 serverSap = NFA_P2P_ANY_SAP;
+
+ /**********************
+ default values for all LLCP parameters:
+ - Local Link MIU (LLCP_MIU)
+ - Option parameter (LLCP_OPT_VALUE)
+ - Response Waiting Time Index (LLCP_WAITING_TIME)
+ - Local Link Timeout (LLCP_LTO_VALUE)
+ - Inactivity Timeout as initiator role (LLCP_INIT_INACTIVITY_TIMEOUT)
+ - Inactivity Timeout as target role (LLCP_TARGET_INACTIVITY_TIMEOUT)
+ - Delay SYMM response (LLCP_DELAY_RESP_TIME)
+ - Data link connection timeout (LLCP_DATA_LINK_CONNECTION_TOUT)
+ - Delay timeout to send first PDU as initiator (LLCP_DELAY_TIME_TO_SEND_FIRST_PDU)
+ ************************/
+ stat = NFA_P2pSetLLCPConfig (LLCP_MAX_MIU,
+ LLCP_OPT_VALUE,
+ LLCP_WAITING_TIME,
+ LLCP_LTO_VALUE,
+ 0, //use 0 for infinite timeout for symmetry procedure when acting as initiator
+ 0, //use 0 for infinite timeout for symmetry procedure when acting as target
+ LLCP_DELAY_RESP_TIME,
+ LLCP_DATA_LINK_CONNECTION_TOUT,
+ LLCP_DELAY_TIME_TO_SEND_FIRST_PDU);
+ if (stat != NFA_STATUS_OK)
+ ALOGE ("%s: fail set LLCP config; error=0x%X", fn, stat);
+
+ if (sSnepServiceName.compare(mServiceName) == 0)
+ serverSap = LLCP_SAP_SNEP; //LLCP_SAP_SNEP == 4
+
+ {
+ SyncEventGuard guard (mRegServerEvent);
+ stat = NFA_P2pRegisterServer (serverSap, NFA_P2P_DLINK_TYPE, const_cast<char*>(mServiceName.c_str()),
+ PeerToPeer::nfaServerCallback);
+ if (stat != NFA_STATUS_OK)
+ {
+ ALOGE ("%s: fail register p2p server; error=0x%X", fn, stat);
+ return (false);
+ }
+ ALOGD ("%s: wait for listen-completion event", fn);
+ // Wait for NFA_P2P_REG_SERVER_EVT
+ mRegServerEvent.wait ();
+ }
+
+ return (mNfaP2pServerHandle != NFA_HANDLE_INVALID);
+}
+
+bool P2pServer::accept(PeerToPeer::tJNI_HANDLE serverJniHandle, PeerToPeer::tJNI_HANDLE connJniHandle,
+ int maxInfoUnit, int recvWindow)
+{
+ static const char fn [] = "P2pServer::accept";
+ tNFA_STATUS nfaStat = NFA_STATUS_OK;
+
+ sp<NfaConn> connection = allocateConnection(connJniHandle);
+ if (connection == NULL) {
+ ALOGE ("%s: failed to allocate new server connection", fn);
+ return false;
+ }
+
+ {
+ // Wait for NFA_P2P_CONN_REQ_EVT or NFA_NDEF_DATA_EVT when remote device requests connection
+ SyncEventGuard guard (mConnRequestEvent);
+ ALOGD ("%s: serverJniHandle: %u; connJniHandle: %u; wait for incoming connection", fn,
+ serverJniHandle, connJniHandle);
+ mConnRequestEvent.wait();
+ ALOGD ("%s: serverJniHandle: %u; connJniHandle: %u; nfa conn h: 0x%X; got incoming connection", fn,
+ serverJniHandle, connJniHandle, connection->mNfaConnHandle);
+ }
+
+ if (connection->mNfaConnHandle == NFA_HANDLE_INVALID)
+ {
+ removeServerConnection(connJniHandle);
+ ALOGD ("%s: no handle assigned", fn);
+ return (false);
+ }
+
+ ALOGD ("%s: serverJniHandle: %u; connJniHandle: %u; nfa conn h: 0x%X; try accept", fn,
+ serverJniHandle, connJniHandle, connection->mNfaConnHandle);
+ nfaStat = NFA_P2pAcceptConn (connection->mNfaConnHandle, maxInfoUnit, recvWindow);
+
+ if (nfaStat != NFA_STATUS_OK)
+ {
+ ALOGE ("%s: fail to accept remote; error=0x%X", fn, nfaStat);
+ return (false);
+ }
+
+ ALOGD ("%s: exit; serverJniHandle: %u; connJniHandle: %u; nfa conn h: 0x%X", fn,
+ serverJniHandle, connJniHandle, connection->mNfaConnHandle);
+ return (true);
+}
+
+void P2pServer::unblockAll()
+{
+ AutoMutex mutex(mMutex);
+ for (int jj = 0; jj < MAX_NFA_CONNS_PER_SERVER; jj++)
+ {
+ if (mServerConn[jj] != NULL)
+ {
+ mServerConn[jj]->mNfaConnHandle = NFA_HANDLE_INVALID;
+ {
+ SyncEventGuard guard1 (mServerConn[jj]->mCongEvent);
+ mServerConn[jj]->mCongEvent.notifyOne (); //unblock write (if congested)
+ }
+ {
+ SyncEventGuard guard2 (mServerConn[jj]->mReadEvent);
+ mServerConn[jj]->mReadEvent.notifyOne (); //unblock receive()
+ }
+ }
+ }
+}
+
+sp<NfaConn> P2pServer::allocateConnection (PeerToPeer::tJNI_HANDLE jniHandle)
+{
+ AutoMutex mutex(mMutex);
+ // First, find a free connection block to handle the connection
+ for (int ii = 0; ii < MAX_NFA_CONNS_PER_SERVER; ii++)
+ {
+ if (mServerConn[ii] == NULL)
+ {
+ mServerConn[ii] = new NfaConn;
+ mServerConn[ii]->mJniHandle = jniHandle;
+ return mServerConn[ii];
+ }
+ }
+
+ return NULL;
+}
+
+
+/*******************************************************************************
+**
+** Function: findServerConnection
+**
+** Description: Find a P2pServer that has the handle.
+** nfaConnHandle: NFA connection handle.
+**
+** Returns: P2pServer object.
+**
+*******************************************************************************/
+sp<NfaConn> P2pServer::findServerConnection (tNFA_HANDLE nfaConnHandle)
+{
+ int jj = 0;
+
+ AutoMutex mutex(mMutex);
+ for (jj = 0; jj < MAX_NFA_CONNS_PER_SERVER; jj++)
+ {
+ if ( (mServerConn[jj] != NULL) && (mServerConn[jj]->mNfaConnHandle == nfaConnHandle) )
+ return (mServerConn[jj]);
+ }
+
+ // If here, not found
+ return (NULL);
+}
+
+/*******************************************************************************
+**
+** Function: findServerConnection
+**
+** Description: Find a P2pServer that has the handle.
+** nfaConnHandle: NFA connection handle.
+**
+** Returns: P2pServer object.
+**
+*******************************************************************************/
+sp<NfaConn> P2pServer::findServerConnection (PeerToPeer::tJNI_HANDLE jniHandle)
+{
+ int jj = 0;
+
+ AutoMutex mutex(mMutex);
+ for (jj = 0; jj < MAX_NFA_CONNS_PER_SERVER; jj++)
+ {
+ if ( (mServerConn[jj] != NULL) && (mServerConn[jj]->mJniHandle == jniHandle) )
+ return (mServerConn[jj]);
+ }
+
+ // If here, not found
+ return (NULL);
+}
+
+/*******************************************************************************
+**
+** Function: removeServerConnection
+**
+** Description: Find a P2pServer that has the handle.
+** nfaConnHandle: NFA connection handle.
+**
+** Returns: P2pServer object.
+**
+*******************************************************************************/
+bool P2pServer::removeServerConnection (PeerToPeer::tJNI_HANDLE jniHandle)
+{
+ int jj = 0;
+
+ AutoMutex mutex(mMutex);
+ for (jj = 0; jj < MAX_NFA_CONNS_PER_SERVER; jj++)
+ {
+ if ( (mServerConn[jj] != NULL) && (mServerConn[jj]->mJniHandle == jniHandle) ) {
+ mServerConn[jj] = NULL;
+ return true;
+ }
+ }
+
+ // If here, not found
+ return false;
+}
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+
+
+/*******************************************************************************
+**
+** Function: P2pClient
+**
+** Description: Initialize member variables.
+**
+** Returns: None
+**
+*******************************************************************************/
+P2pClient::P2pClient ()
+: mNfaP2pClientHandle (NFA_HANDLE_INVALID),
+ mIsConnecting (false)
+{
+ mClientConn = new NfaConn();
+}
+
+
+/*******************************************************************************
+**
+** Function: ~P2pClient
+**
+** Description: Free all resources.
+**
+** Returns: None
+**
+*******************************************************************************/
+P2pClient::~P2pClient ()
+{
+}
+
+
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+
+
+/*******************************************************************************
+**
+** Function: NfaConn
+**
+** Description: Initialize member variables.
+**
+** Returns: None
+**
+*******************************************************************************/
+NfaConn::NfaConn()
+: mNfaConnHandle (NFA_HANDLE_INVALID),
+ mJniHandle (0),
+ mMaxInfoUnit (0),
+ mRecvWindow (0),
+ mRemoteMaxInfoUnit (0),
+ mRemoteRecvWindow (0)
+{
+}
+
diff --git a/nci/jni/PeerToPeer.h b/nci/jni/PeerToPeer.h
new file mode 100644
index 0000000..3e8ffec
--- /dev/null
+++ b/nci/jni/PeerToPeer.h
@@ -0,0 +1,779 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+/*
+ * Communicate with a peer using NFC-DEP, LLCP, SNEP.
+ */
+#pragma once
+#include <utils/RefBase.h>
+#include <utils/StrongPointer.h>
+#include "SyncEvent.h"
+#include "NfcJniUtil.h"
+#include <string>
+extern "C"
+{
+ #include "nfa_p2p_api.h"
+ #include "nfa_snep_api.h"
+}
+
+class P2pServer;
+class P2pClient;
+class NfaConn;
+#define MAX_NFA_CONNS_PER_SERVER 5
+
+/*****************************************************************************
+**
+** Name: PeerToPeer
+**
+** Description: Communicate with a peer using NFC-DEP, LLCP, SNEP.
+**
+*****************************************************************************/
+class PeerToPeer
+{
+public:
+ typedef unsigned int tJNI_HANDLE;
+
+ /*******************************************************************************
+ **
+ ** Function: PeerToPeer
+ **
+ ** Description: Initialize member variables.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ PeerToPeer ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: ~PeerToPeer
+ **
+ ** Description: Free all resources.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ ~PeerToPeer ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: getInstance
+ **
+ ** Description: Get the singleton PeerToPeer object.
+ **
+ ** Returns: Singleton PeerToPeer object.
+ **
+ *******************************************************************************/
+ static PeerToPeer& getInstance();
+
+
+ /*******************************************************************************
+ **
+ ** Function: initialize
+ **
+ ** Description: Initialize member variables.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void initialize ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: llcpActivatedHandler
+ **
+ ** Description: Receive LLLCP-activated event from stack.
+ ** nat: JVM-related data.
+ ** activated: Event data.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void llcpActivatedHandler (nfc_jni_native_data* nativeData, tNFA_LLCP_ACTIVATED& activated);
+
+
+ /*******************************************************************************
+ **
+ ** Function: llcpDeactivatedHandler
+ **
+ ** Description: Receive LLLCP-deactivated event from stack.
+ ** nat: JVM-related data.
+ ** deactivated: Event data.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void llcpDeactivatedHandler (nfc_jni_native_data* nativeData, tNFA_LLCP_DEACTIVATED& deactivated);
+
+
+ /*******************************************************************************
+ **
+ ** Function: connectionEventHandler
+ **
+ ** Description: Receive events from the stack.
+ ** event: Event code.
+ ** eventData: Event data.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void connectionEventHandler (UINT8 event, tNFA_CONN_EVT_DATA* eventData);
+
+
+ /*******************************************************************************
+ **
+ ** Function: registerServer
+ **
+ ** Description: Let a server start listening for peer's connection request.
+ ** jniHandle: Connection handle.
+ ** serviceName: Server's service name.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool registerServer (tJNI_HANDLE jniHandle, const char* serviceName);
+
+
+ /*******************************************************************************
+ **
+ ** Function: deregisterServer
+ **
+ ** Description: Stop a P2pServer from listening for peer.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool deregisterServer (tJNI_HANDLE jniHandle);
+
+
+ /*******************************************************************************
+ **
+ ** Function: accept
+ **
+ ** Description: Accept a peer's request to connect.
+ ** serverJniHandle: Server's handle.
+ ** connJniHandle: Connection handle.
+ ** maxInfoUnit: Maximum information unit.
+ ** recvWindow: Receive window size.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool accept (tJNI_HANDLE serverJniHandle, tJNI_HANDLE connJniHandle, int maxInfoUnit, int recvWindow);
+
+
+ /*******************************************************************************
+ **
+ ** Function: createClient
+ **
+ ** Description: Create a P2pClient object for a new out-bound connection.
+ ** jniHandle: Connection handle.
+ ** miu: Maximum information unit.
+ ** rw: Receive window size.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool createClient (tJNI_HANDLE jniHandle, UINT16 miu, UINT8 rw);
+
+
+ /*******************************************************************************
+ **
+ ** Function: connectConnOriented
+ **
+ ** Description: Estabish a connection-oriented connection to a peer.
+ ** jniHandle: Connection handle.
+ ** serviceName: Peer's service name.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool connectConnOriented (tJNI_HANDLE jniHandle, const char* serviceName);
+
+
+ /*******************************************************************************
+ **
+ ** Function: connectConnOriented
+ **
+ ** Description: Estabish a connection-oriented connection to a peer.
+ ** jniHandle: Connection handle.
+ ** destinationSap: Peer's service access point.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool connectConnOriented (tJNI_HANDLE jniHandle, UINT8 destinationSap);
+
+
+ /*******************************************************************************
+ **
+ ** Function: send
+ **
+ ** Description: Send data to peer.
+ ** jniHandle: Handle of connection.
+ ** buffer: Buffer of data.
+ ** bufferLen: Length of data.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool send (tJNI_HANDLE jniHandle, UINT8* buffer, UINT16 bufferLen);
+
+
+ /*******************************************************************************
+ **
+ ** Function: receive
+ **
+ ** Description: Receive data from peer.
+ ** jniHandle: Handle of connection.
+ ** buffer: Buffer to store data.
+ ** bufferLen: Max length of buffer.
+ ** actualLen: Actual length received.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool receive (tJNI_HANDLE jniHandle, UINT8* buffer, UINT16 bufferLen, UINT16& actualLen);
+
+
+ /*******************************************************************************
+ **
+ ** Function: disconnectConnOriented
+ **
+ ** Description: Disconnect a connection-oriented connection with peer.
+ ** jniHandle: Handle of connection.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool disconnectConnOriented (tJNI_HANDLE jniHandle);
+
+
+ /*******************************************************************************
+ **
+ ** Function: getRemoteMaxInfoUnit
+ **
+ ** Description: Get peer's max information unit.
+ ** jniHandle: Handle of the connection.
+ **
+ ** Returns: Peer's max information unit.
+ **
+ *******************************************************************************/
+ UINT16 getRemoteMaxInfoUnit (tJNI_HANDLE jniHandle);
+
+
+ /*******************************************************************************
+ **
+ ** Function: getRemoteRecvWindow
+ **
+ ** Description: Get peer's receive window size.
+ ** jniHandle: Handle of the connection.
+ **
+ ** Returns: Peer's receive window size.
+ **
+ *******************************************************************************/
+ UINT8 getRemoteRecvWindow (tJNI_HANDLE jniHandle);
+
+
+ /*******************************************************************************
+ **
+ ** Function: setP2pListenMask
+ **
+ ** Description: Sets the p2p listen technology mask.
+ ** p2pListenMask: the p2p listen mask to be set?
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void setP2pListenMask (tNFA_TECHNOLOGY_MASK p2pListenMask);
+
+ /*******************************************************************************
+ **
+ ** Function: enableP2pListening
+ **
+ ** Description: Start/stop polling/listening to peer that supports P2P.
+ ** isEnable: Is enable polling/listening?
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void enableP2pListening (bool isEnable);
+
+
+ /*******************************************************************************
+ **
+ ** Function: handleNfcOnOff
+ **
+ ** Description: Handle events related to turning NFC on/off by the user.
+ ** isOn: Is NFC turning on?
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void handleNfcOnOff (bool isOn);
+
+
+ /*******************************************************************************
+ **
+ ** Function: getNextJniHandle
+ **
+ ** Description: Get a new JNI handle.
+ **
+ ** Returns: A new JNI handle.
+ **
+ *******************************************************************************/
+ tJNI_HANDLE getNewJniHandle ();
+
+ /*******************************************************************************
+ **
+ ** Function: nfaServerCallback
+ **
+ ** Description: Receive LLCP-related events from the stack.
+ ** p2pEvent: Event code.
+ ** eventData: Event data.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ static void nfaServerCallback (tNFA_P2P_EVT p2pEvent, tNFA_P2P_EVT_DATA *eventData);
+
+
+ /*******************************************************************************
+ **
+ ** Function: nfaClientCallback
+ **
+ ** Description: Receive LLCP-related events from the stack.
+ ** p2pEvent: Event code.
+ ** eventData: Event data.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ static void nfaClientCallback (tNFA_P2P_EVT p2pEvent, tNFA_P2P_EVT_DATA *eventData);
+
+private:
+ static const int sMax = 10;
+ static PeerToPeer sP2p;
+
+ // Variables below only accessed from a single thread
+ UINT16 mRemoteWKS; // Peer's well known services
+ bool mIsP2pListening; // If P2P listening is enabled or not
+ tNFA_TECHNOLOGY_MASK mP2pListenTechMask; // P2P Listen mask
+
+ // Variable below is protected by mNewJniHandleMutex
+ tJNI_HANDLE mNextJniHandle;
+
+ // Variables below protected by mMutex
+ // A note on locking order: mMutex in PeerToPeer is *ALWAYS*
+ // locked before any locks / guards in P2pServer / P2pClient
+ Mutex mMutex;
+ android::sp<P2pServer> mServers [sMax];
+ android::sp<P2pClient> mClients [sMax];
+
+ // Synchronization variables
+ SyncEvent mSetTechEvent; // completion event for NFA_SetP2pListenTech()
+ SyncEvent mSnepDefaultServerStartStopEvent; // completion event for NFA_SnepStartDefaultServer(), NFA_SnepStopDefaultServer()
+ SyncEvent mSnepRegisterEvent; // completion event for NFA_SnepRegisterClient()
+ Mutex mDisconnectMutex; // synchronize the disconnect operation
+ Mutex mNewJniHandleMutex; // synchronize the creation of a new JNI handle
+
+ /*******************************************************************************
+ **
+ ** Function: snepClientCallback
+ **
+ ** Description: Receive SNEP-related events from the stack.
+ ** snepEvent: Event code.
+ ** eventData: Event data.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ static void snepClientCallback (tNFA_SNEP_EVT snepEvent, tNFA_SNEP_EVT_DATA *eventData);
+
+
+ /*******************************************************************************
+ **
+ ** Function: ndefTypeCallback
+ **
+ ** Description: Receive NDEF-related events from the stack.
+ ** ndefEvent: Event code.
+ ** eventData: Event data.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ static void ndefTypeCallback (tNFA_NDEF_EVT event, tNFA_NDEF_EVT_DATA *evetnData);
+
+
+ /*******************************************************************************
+ **
+ ** Function: findServer
+ **
+ ** Description: Find a PeerToPeer object by connection handle.
+ ** nfaP2pServerHandle: Connectin handle.
+ **
+ ** Returns: PeerToPeer object.
+ **
+ *******************************************************************************/
+ android::sp<P2pServer> findServerLocked (tNFA_HANDLE nfaP2pServerHandle);
+
+
+ /*******************************************************************************
+ **
+ ** Function: findServer
+ **
+ ** Description: Find a PeerToPeer object by connection handle.
+ ** serviceName: service name.
+ **
+ ** Returns: PeerToPeer object.
+ **
+ *******************************************************************************/
+ android::sp<P2pServer> findServerLocked (tJNI_HANDLE jniHandle);
+
+
+ /*******************************************************************************
+ **
+ ** Function: findServer
+ **
+ ** Description: Find a PeerToPeer object by service name
+ ** serviceName: service name.
+ **
+ ** Returns: PeerToPeer object.
+ **
+ *******************************************************************************/
+ android::sp<P2pServer> findServerLocked (const char *serviceName);
+
+
+ /*******************************************************************************
+ **
+ ** Function: removeServer
+ **
+ ** Description: Free resources related to a server.
+ ** jniHandle: Connection handle.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void removeServer (tJNI_HANDLE jniHandle);
+
+
+ /*******************************************************************************
+ **
+ ** Function: removeConn
+ **
+ ** Description: Free resources related to a connection.
+ ** jniHandle: Connection handle.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void removeConn (tJNI_HANDLE jniHandle);
+
+
+ /*******************************************************************************
+ **
+ ** Function: createDataLinkConn
+ **
+ ** Description: Establish a connection-oriented connection to a peer.
+ ** jniHandle: Connection handle.
+ ** serviceName: Peer's service name.
+ ** destinationSap: Peer's service access point.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool createDataLinkConn (tJNI_HANDLE jniHandle, const char* serviceName, UINT8 destinationSap);
+
+
+ /*******************************************************************************
+ **
+ ** Function: findClient
+ **
+ ** Description: Find a PeerToPeer object with a client connection handle.
+ ** nfaConnHandle: Connection handle.
+ **
+ ** Returns: PeerToPeer object.
+ **
+ *******************************************************************************/
+ android::sp<P2pClient> findClient (tNFA_HANDLE nfaConnHandle);
+
+
+ /*******************************************************************************
+ **
+ ** Function: findClient
+ **
+ ** Description: Find a PeerToPeer object with a client connection handle.
+ ** jniHandle: Connection handle.
+ **
+ ** Returns: PeerToPeer object.
+ **
+ *******************************************************************************/
+ android::sp<P2pClient> findClient (tJNI_HANDLE jniHandle);
+
+
+ /*******************************************************************************
+ **
+ ** Function: findClientCon
+ **
+ ** Description: Find a PeerToPeer object with a client connection handle.
+ ** nfaConnHandle: Connection handle.
+ **
+ ** Returns: PeerToPeer object.
+ **
+ *******************************************************************************/
+ android::sp<P2pClient> findClientCon (tNFA_HANDLE nfaConnHandle);
+
+
+ /*******************************************************************************
+ **
+ ** Function: findConnection
+ **
+ ** Description: Find a PeerToPeer object with a connection handle.
+ ** nfaConnHandle: Connection handle.
+ **
+ ** Returns: PeerToPeer object.
+ **
+ *******************************************************************************/
+ android::sp<NfaConn> findConnection (tNFA_HANDLE nfaConnHandle);
+
+
+ /*******************************************************************************
+ **
+ ** Function: findConnection
+ **
+ ** Description: Find a PeerToPeer object with a connection handle.
+ ** jniHandle: Connection handle.
+ **
+ ** Returns: PeerToPeer object.
+ **
+ *******************************************************************************/
+ android::sp<NfaConn> findConnection (tJNI_HANDLE jniHandle);
+};
+
+
+/*****************************************************************************
+**
+** Name: NfaConn
+**
+** Description: Store information about a connection related to a peer.
+**
+*****************************************************************************/
+class NfaConn : public android::RefBase
+{
+public:
+ tNFA_HANDLE mNfaConnHandle; // NFA handle of the P2P connection
+ PeerToPeer::tJNI_HANDLE mJniHandle; // JNI handle of the P2P connection
+ UINT16 mMaxInfoUnit;
+ UINT8 mRecvWindow;
+ UINT16 mRemoteMaxInfoUnit;
+ UINT8 mRemoteRecvWindow;
+ SyncEvent mReadEvent; // event for reading
+ SyncEvent mCongEvent; // event for congestion
+ SyncEvent mDisconnectingEvent; // event for disconnecting
+
+
+ /*******************************************************************************
+ **
+ ** Function: NfaConn
+ **
+ ** Description: Initialize member variables.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ NfaConn();
+};
+
+
+/*****************************************************************************
+**
+** Name: P2pServer
+**
+** Description: Store information about an in-bound connection from a peer.
+**
+*****************************************************************************/
+class P2pServer : public android::RefBase
+{
+public:
+ static const std::string sSnepServiceName;
+
+ tNFA_HANDLE mNfaP2pServerHandle; // NFA p2p handle of local server
+ PeerToPeer::tJNI_HANDLE mJniHandle; // JNI Handle
+ SyncEvent mRegServerEvent; // for NFA_P2pRegisterServer()
+ SyncEvent mConnRequestEvent; // for accept()
+ std::string mServiceName;
+
+ /*******************************************************************************
+ **
+ ** Function: P2pServer
+ **
+ ** Description: Initialize member variables.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ P2pServer (PeerToPeer::tJNI_HANDLE jniHandle, const char* serviceName);
+
+ /*******************************************************************************
+ **
+ ** Function: registerWithStack
+ **
+ ** Description: Register this server with the stack.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool registerWithStack();
+
+ /*******************************************************************************
+ **
+ ** Function: accept
+ **
+ ** Description: Accept a peer's request to connect.
+ ** serverJniHandle: Server's handle.
+ ** connJniHandle: Connection handle.
+ ** maxInfoUnit: Maximum information unit.
+ ** recvWindow: Receive window size.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool accept (PeerToPeer::tJNI_HANDLE serverJniHandle, PeerToPeer::tJNI_HANDLE connJniHandle,
+ int maxInfoUnit, int recvWindow);
+
+ /*******************************************************************************
+ **
+ ** Function: unblockAll
+ **
+ ** Description: Unblocks all server connections
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ void unblockAll();
+
+ /*******************************************************************************
+ **
+ ** Function: findServerConnection
+ **
+ ** Description: Find a P2pServer that has the handle.
+ ** nfaConnHandle: NFA connection handle.
+ **
+ ** Returns: P2pServer object.
+ **
+ *******************************************************************************/
+ android::sp<NfaConn> findServerConnection (tNFA_HANDLE nfaConnHandle);
+
+ /*******************************************************************************
+ **
+ ** Function: findServerConnection
+ **
+ ** Description: Find a P2pServer that has the handle.
+ ** jniHandle: JNI connection handle.
+ **
+ ** Returns: P2pServer object.
+ **
+ *******************************************************************************/
+ android::sp<NfaConn> findServerConnection (PeerToPeer::tJNI_HANDLE jniHandle);
+
+ /*******************************************************************************
+ **
+ ** Function: removeServerConnection
+ **
+ ** Description: Remove a server connection with the provided handle.
+ ** jniHandle: JNI connection handle.
+ **
+ ** Returns: True if connection found and removed.
+ **
+ *******************************************************************************/
+ bool removeServerConnection(PeerToPeer::tJNI_HANDLE jniHandle);
+
+private:
+ Mutex mMutex;
+ // mServerConn is protected by mMutex
+ android::sp<NfaConn> mServerConn[MAX_NFA_CONNS_PER_SERVER];
+
+ /*******************************************************************************
+ **
+ ** Function: allocateConnection
+ **
+ ** Description: Allocate a new connection to accept on
+ ** jniHandle: JNI connection handle.
+ **
+ ** Returns: Allocated connection object
+ ** NULL if the maximum number of connections was reached
+ **
+ *******************************************************************************/
+ android::sp<NfaConn> allocateConnection (PeerToPeer::tJNI_HANDLE jniHandle);
+};
+
+
+/*****************************************************************************
+**
+** Name: P2pClient
+**
+** Description: Store information about an out-bound connection to a peer.
+**
+*****************************************************************************/
+class P2pClient : public android::RefBase
+{
+public:
+ tNFA_HANDLE mNfaP2pClientHandle; // NFA p2p handle of client
+ bool mIsConnecting; // Set true while connecting
+ android::sp<NfaConn> mClientConn;
+ SyncEvent mRegisteringEvent; // For client registration
+ SyncEvent mConnectingEvent; // for NFA_P2pConnectByName or Sap()
+ SyncEvent mSnepEvent; // To wait for SNEP completion
+
+ /*******************************************************************************
+ **
+ ** Function: P2pClient
+ **
+ ** Description: Initialize member variables.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ P2pClient ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: ~P2pClient
+ **
+ ** Description: Free all resources.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ ~P2pClient ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: unblock
+ **
+ ** Description: Unblocks any threads that are locked on this connection
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void unblock();
+};
+
diff --git a/nci/jni/Pn544Interop.cpp b/nci/jni/Pn544Interop.cpp
new file mode 100644
index 0000000..be92c75
--- /dev/null
+++ b/nci/jni/Pn544Interop.cpp
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+/*****************************************************************************
+**
+** Name: Pn544Interop.cpp
+**
+** Description: Implement operations that provide compatibility with NXP
+** PN544 controller. Specifically facilitate peer-to-peer
+** operations with PN544 controller.
+**
+*****************************************************************************/
+#include "OverrideLog.h"
+#include "Pn544Interop.h"
+#include "IntervalTimer.h"
+#include "Mutex.h"
+#include "NfcTag.h"
+namespace android
+{
+ extern void startStopPolling (bool isStartPolling);
+}
+
+
+/*****************************************************************************
+**
+** private variables and functions
+**
+*****************************************************************************/
+
+
+static const int gIntervalTime = 1000; //millisecond between the check to restore polling
+static IntervalTimer gTimer;
+static Mutex gMutex;
+static void pn544InteropStartPolling (union sigval); //callback function for interval timer
+static bool gIsBusy = false; //is timer busy?
+static bool gAbortNow = false; //stop timer during next callback
+
+
+/*******************************************************************************
+**
+** Function: pn544InteropStopPolling
+**
+** Description: Stop polling to let NXP PN544 controller poll.
+** PN544 should activate in P2P mode.
+**
+** Returns: None
+**
+*******************************************************************************/
+void pn544InteropStopPolling ()
+{
+ ALOGD ("%s: enter", __FUNCTION__);
+ gMutex.lock ();
+ gTimer.kill ();
+ android::startStopPolling (false);
+ gIsBusy = true;
+ gAbortNow = false;
+ gTimer.set (gIntervalTime, pn544InteropStartPolling); //after some time, start polling again
+ gMutex.unlock ();
+ ALOGD ("%s: exit", __FUNCTION__);
+}
+
+
+/*******************************************************************************
+**
+** Function: pn544InteropStartPolling
+**
+** Description: Start polling when activation state is idle.
+** sigval: Unused.
+**
+** Returns: None
+**
+*******************************************************************************/
+void pn544InteropStartPolling (union sigval)
+{
+ ALOGD ("%s: enter", __FUNCTION__);
+ gMutex.lock ();
+ NfcTag::ActivationState state = NfcTag::getInstance ().getActivationState ();
+
+ if (gAbortNow)
+ {
+ ALOGD ("%s: abort now", __FUNCTION__);
+ gIsBusy = false;
+ goto TheEnd;
+ }
+
+ if (state == NfcTag::Idle)
+ {
+ ALOGD ("%s: start polling", __FUNCTION__);
+ android::startStopPolling (true);
+ gIsBusy = false;
+ }
+ else
+ {
+ ALOGD ("%s: try again later", __FUNCTION__);
+ gTimer.set (gIntervalTime, pn544InteropStartPolling); //after some time, start polling again
+ }
+
+TheEnd:
+ gMutex.unlock ();
+ ALOGD ("%s: exit", __FUNCTION__);
+}
+
+
+/*******************************************************************************
+**
+** Function: pn544InteropIsBusy
+**
+** Description: Is the code performing operations?
+**
+** Returns: True if the code is busy.
+**
+*******************************************************************************/
+bool pn544InteropIsBusy ()
+{
+ bool isBusy = false;
+ gMutex.lock ();
+ isBusy = gIsBusy;
+ gMutex.unlock ();
+ ALOGD ("%s: %u", __FUNCTION__, isBusy);
+ return isBusy;
+}
+
+
+/*******************************************************************************
+**
+** Function: pn544InteropAbortNow
+**
+** Description: Request to abort all operations.
+**
+** Returns: None.
+**
+*******************************************************************************/
+void pn544InteropAbortNow ()
+{
+ ALOGD ("%s", __FUNCTION__);
+ gMutex.lock ();
+ gAbortNow = true;
+ gMutex.unlock ();
+}
+
diff --git a/nci/jni/Pn544Interop.h b/nci/jni/Pn544Interop.h
new file mode 100644
index 0000000..c9a2df6
--- /dev/null
+++ b/nci/jni/Pn544Interop.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+/*****************************************************************************
+**
+** Name: Pn544Interop.h
+**
+** Description: Implement operations that provide compatibility with NXP
+** PN544 controller. Specifically facilitate peer-to-peer
+** operations with PN544 controller.
+**
+*****************************************************************************/
+#pragma once
+#include "NfcJniUtil.h"
+
+
+/*******************************************************************************
+**
+** Function: pn544InteropStopPolling
+**
+** Description: Stop polling to let NXP PN544 controller poll.
+** PN544 should activate in P2P mode.
+**
+** Returns: None
+**
+*******************************************************************************/
+void pn544InteropStopPolling ();
+
+
+/*******************************************************************************
+**
+** Function: pn544InteropIsBusy
+**
+** Description: Is the code performing operations?
+**
+** Returns: True if the code is busy.
+**
+*******************************************************************************/
+bool pn544InteropIsBusy ();
+
+
+/*******************************************************************************
+**
+** Function: pn544InteropAbortNow
+**
+** Description: Request to abort all operations.
+**
+** Returns: None.
+**
+*******************************************************************************/
+void pn544InteropAbortNow ();
diff --git a/nci/jni/PowerSwitch.cpp b/nci/jni/PowerSwitch.cpp
new file mode 100755
index 0000000..9d58c74
--- /dev/null
+++ b/nci/jni/PowerSwitch.cpp
@@ -0,0 +1,439 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+/*
+ * Adjust the controller's power states.
+ */
+#include "OverrideLog.h"
+#include "PowerSwitch.h"
+#include "NfcJniUtil.h"
+#include "config.h"
+#include "SecureElement.h"
+
+
+namespace android
+{
+ void doStartupConfig ();
+}
+
+
+PowerSwitch PowerSwitch::sPowerSwitch;
+const PowerSwitch::PowerActivity PowerSwitch::DISCOVERY=0x01;
+const PowerSwitch::PowerActivity PowerSwitch::SE_ROUTING=0x02;
+const PowerSwitch::PowerActivity PowerSwitch::SE_CONNECTED=0x04;
+
+/*******************************************************************************
+**
+** Function: PowerSwitch
+**
+** Description: Initialize member variables.
+**
+** Returns: None
+**
+*******************************************************************************/
+PowerSwitch::PowerSwitch ()
+: mCurrLevel (UNKNOWN_LEVEL),
+ mCurrDeviceMgtPowerState (NFA_DM_PWR_STATE_UNKNOWN),
+ mDesiredScreenOffPowerState (0),
+ mCurrActivity(0)
+{
+}
+
+
+/*******************************************************************************
+**
+** Function: ~PowerSwitch
+**
+** Description: Release all resources.
+**
+** Returns: None
+**
+*******************************************************************************/
+PowerSwitch::~PowerSwitch ()
+{
+}
+
+
+/*******************************************************************************
+**
+** Function: getInstance
+**
+** Description: Get the singleton of this object.
+**
+** Returns: Reference to this object.
+**
+*******************************************************************************/
+PowerSwitch& PowerSwitch::getInstance ()
+{
+ return sPowerSwitch;
+}
+
+
+/*******************************************************************************
+**
+** Function: initialize
+**
+** Description: Initialize member variables.
+**
+** Returns: None
+**
+*******************************************************************************/
+void PowerSwitch::initialize (PowerLevel level)
+{
+ static const char fn [] = "PowerSwitch::initialize";
+
+ mMutex.lock ();
+
+ ALOGD ("%s: level=%s (%u)", fn, powerLevelToString(level), level);
+ GetNumValue (NAME_SCREEN_OFF_POWER_STATE, &mDesiredScreenOffPowerState, sizeof(mDesiredScreenOffPowerState));
+ ALOGD ("%s: desired screen-off state=%d", fn, mDesiredScreenOffPowerState);
+
+ switch (level)
+ {
+ case FULL_POWER:
+ mCurrDeviceMgtPowerState = NFA_DM_PWR_MODE_FULL;
+ mCurrLevel = level;
+ break;
+
+ case UNKNOWN_LEVEL:
+ mCurrDeviceMgtPowerState = NFA_DM_PWR_STATE_UNKNOWN;
+ mCurrLevel = level;
+ break;
+
+ default:
+ ALOGE ("%s: not handled", fn);
+ break;
+ }
+ mMutex.unlock ();
+}
+
+
+/*******************************************************************************
+**
+** Function: getLevel
+**
+** Description: Get the current power level of the controller.
+**
+** Returns: Power level.
+**
+*******************************************************************************/
+PowerSwitch::PowerLevel PowerSwitch::getLevel ()
+{
+ PowerLevel level = UNKNOWN_LEVEL;
+ mMutex.lock ();
+ level = mCurrLevel;
+ mMutex.unlock ();
+ return level;
+}
+
+
+/*******************************************************************************
+**
+** Function: setLevel
+**
+** Description: Set the controller's power level.
+** level: power level.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool PowerSwitch::setLevel (PowerLevel newLevel)
+{
+ static const char fn [] = "PowerSwitch::setLevel";
+ bool retval = false;
+
+ mMutex.lock ();
+
+ ALOGD ("%s: level=%s (%u)", fn, powerLevelToString(newLevel), newLevel);
+ if (mCurrLevel == newLevel)
+ {
+ retval = true;
+ goto TheEnd;
+ }
+
+ switch (newLevel)
+ {
+ case FULL_POWER:
+ if (mCurrDeviceMgtPowerState == NFA_DM_PWR_MODE_OFF_SLEEP)
+ retval = setPowerOffSleepState (false);
+ break;
+
+ case LOW_POWER:
+ case POWER_OFF:
+ if (isPowerOffSleepFeatureEnabled())
+ retval = setPowerOffSleepState (true);
+ else if (mDesiredScreenOffPowerState == 1) //.conf file desires full-power
+ {
+ mCurrLevel = FULL_POWER;
+ retval = true;
+ }
+ break;
+
+ default:
+ ALOGE ("%s: not handled", fn);
+ break;
+ }
+
+TheEnd:
+ mMutex.unlock ();
+ return retval;
+}
+
+/*******************************************************************************
+**
+** Function: setModeOff
+**
+** Description: Set a mode to be deactive.
+**
+** Returns: True if any mode is still active.
+**
+*******************************************************************************/
+bool PowerSwitch::setModeOff (PowerActivity deactivated)
+{
+ bool retVal = false;
+
+ mMutex.lock ();
+ mCurrActivity &= ~deactivated;
+ retVal = mCurrActivity != 0;
+ ALOGD ("PowerSwitch::setModeOff(deactivated=0x%x) : mCurrActivity=0x%x", deactivated, mCurrActivity);
+ mMutex.unlock ();
+ return retVal;
+}
+
+
+/*******************************************************************************
+**
+** Function: setModeOn
+**
+** Description: Set a mode to be active.
+**
+** Returns: True if any mode is active.
+**
+*******************************************************************************/
+bool PowerSwitch::setModeOn (PowerActivity activated)
+{
+ bool retVal = false;
+
+ mMutex.lock ();
+ mCurrActivity |= activated;
+ retVal = mCurrActivity != 0;
+ ALOGD ("PowerSwitch::setModeOn(activated=0x%x) : mCurrActivity=0x%x", activated, mCurrActivity);
+ mMutex.unlock ();
+ return retVal;
+}
+
+
+/*******************************************************************************
+**
+** Function: setPowerOffSleepState
+**
+** Description: Adjust controller's power-off-sleep state.
+** sleep: whether to enter sleep state.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool PowerSwitch::setPowerOffSleepState (bool sleep)
+{
+ static const char fn [] = "PowerSwitch::setPowerOffSleepState";
+ ALOGD ("%s: enter; sleep=%u", fn, sleep);
+ tNFA_STATUS stat = NFA_STATUS_FAILED;
+ bool retval = false;
+
+ if (sleep) //enter power-off-sleep state
+ {
+ //make sure the current power state is ON
+ if (mCurrDeviceMgtPowerState != NFA_DM_PWR_MODE_OFF_SLEEP)
+ {
+ SyncEventGuard guard (mPowerStateEvent);
+ ALOGD ("%s: try power off", fn);
+ stat = NFA_PowerOffSleepMode (TRUE);
+ if (stat == NFA_STATUS_OK)
+ {
+ mPowerStateEvent.wait ();
+ mCurrLevel = LOW_POWER;
+ }
+ else
+ {
+ ALOGE ("%s: API fail; stat=0x%X", fn, stat);
+ goto TheEnd;
+ }
+ }
+ else
+ {
+ ALOGE ("%s: power is not ON; curr device mgt power state=%s (%u)", fn,
+ deviceMgtPowerStateToString (mCurrDeviceMgtPowerState), mCurrDeviceMgtPowerState);
+ goto TheEnd;
+ }
+ }
+ else //exit power-off-sleep state
+ {
+ //make sure the current power state is OFF
+ if (mCurrDeviceMgtPowerState != NFA_DM_PWR_MODE_FULL)
+ {
+ mCurrDeviceMgtPowerState = NFA_DM_PWR_STATE_UNKNOWN;
+ SyncEventGuard guard (mPowerStateEvent);
+ ALOGD ("%s: try full power", fn);
+ stat = NFA_PowerOffSleepMode (FALSE);
+ if (stat == NFA_STATUS_OK)
+ {
+ mPowerStateEvent.wait ();
+ if (mCurrDeviceMgtPowerState != NFA_DM_PWR_MODE_FULL)
+ {
+ ALOGE ("%s: unable to full power; curr device mgt power stat=%s (%u)", fn,
+ deviceMgtPowerStateToString (mCurrDeviceMgtPowerState), mCurrDeviceMgtPowerState);
+ goto TheEnd;
+ }
+ android::doStartupConfig ();
+ mCurrLevel = FULL_POWER;
+ }
+ else
+ {
+ ALOGE ("%s: API fail; stat=0x%X", fn, stat);
+ goto TheEnd;
+ }
+ }
+ else
+ {
+ ALOGE ("%s: not in power-off state; curr device mgt power state=%s (%u)", fn,
+ deviceMgtPowerStateToString (mCurrDeviceMgtPowerState), mCurrDeviceMgtPowerState);
+ goto TheEnd;
+ }
+ }
+
+ retval = true;
+TheEnd:
+ ALOGD ("%s: exit; return %u", fn, retval);
+ return retval;
+}
+
+
+/*******************************************************************************
+**
+** Function: deviceMgtPowerStateToString
+**
+** Description: Decode power level to a string.
+** deviceMgtPowerState: power level.
+**
+** Returns: Text representation of power level.
+**
+*******************************************************************************/
+const char* PowerSwitch::deviceMgtPowerStateToString (UINT8 deviceMgtPowerState)
+{
+ switch (deviceMgtPowerState)
+ {
+ case NFA_DM_PWR_MODE_FULL:
+ return "DM-FULL";
+ case NFA_DM_PWR_MODE_OFF_SLEEP:
+ return "DM-OFF";
+ default:
+ return "DM-unknown????";
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: powerLevelToString
+**
+** Description: Decode power level to a string.
+** level: power level.
+**
+** Returns: Text representation of power level.
+**
+*******************************************************************************/
+const char* PowerSwitch::powerLevelToString (PowerLevel level)
+{
+ switch (level)
+ {
+ case UNKNOWN_LEVEL:
+ return "PS-UNKNOWN";
+ case FULL_POWER:
+ return "PS-FULL";
+ case LOW_POWER:
+ return "PS-LOW-POWER";
+ case POWER_OFF:
+ return "PS-POWER-OFF";
+ default:
+ return "PS-unknown????";
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: abort
+**
+** Description: Abort and unblock currrent operation.
+**
+** Returns: None
+**
+*******************************************************************************/
+void PowerSwitch::abort ()
+{
+ static const char fn [] = "PowerSwitch::abort";
+ ALOGD ("%s", fn);
+ SyncEventGuard guard (mPowerStateEvent);
+ mPowerStateEvent.notifyOne ();
+}
+
+
+/*******************************************************************************
+**
+** Function: deviceManagementCallback
+**
+** Description: Callback function for the stack.
+** event: event ID.
+** eventData: event's data.
+**
+** Returns: None
+**
+*******************************************************************************/
+void PowerSwitch::deviceManagementCallback (UINT8 event, tNFA_DM_CBACK_DATA* eventData)
+{
+ static const char fn [] = "PowerSwitch::deviceManagementCallback";
+
+ switch (event)
+ {
+ case NFA_DM_PWR_MODE_CHANGE_EVT:
+ {
+ tNFA_DM_PWR_MODE_CHANGE& power_mode = eventData->power_mode;
+ ALOGD ("%s: NFA_DM_PWR_MODE_CHANGE_EVT; status=%u; device mgt power mode=%s (%u)", fn,
+ power_mode.status, sPowerSwitch.deviceMgtPowerStateToString (power_mode.power_mode), power_mode.power_mode);
+ SyncEventGuard guard (sPowerSwitch.mPowerStateEvent);
+ if (power_mode.status == NFA_STATUS_OK)
+ sPowerSwitch.mCurrDeviceMgtPowerState = power_mode.power_mode;
+ sPowerSwitch.mPowerStateEvent.notifyOne ();
+ }
+ break;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: isPowerOffSleepFeatureEnabled
+**
+** Description: Whether power-off-sleep feature is enabled in .conf file.
+**
+** Returns: True if feature is enabled.
+**
+*******************************************************************************/
+bool PowerSwitch::isPowerOffSleepFeatureEnabled ()
+{
+ return mDesiredScreenOffPowerState == 0;
+}
+
diff --git a/nci/jni/PowerSwitch.h b/nci/jni/PowerSwitch.h
new file mode 100755
index 0000000..d311c23
--- /dev/null
+++ b/nci/jni/PowerSwitch.h
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+/*
+ * Adjust the controller's power states.
+ */
+#pragma once
+#include "nfa_api.h"
+#include "SyncEvent.h"
+
+
+/*****************************************************************************
+**
+** Name: PowerSwitch
+**
+** Description: Adjust the controller's power states.
+**
+*****************************************************************************/
+class PowerSwitch
+{
+public:
+
+
+ /*******************************************************************************
+ **
+ ** Description: UNKNOWN_LEVEL: power level is unknown because the stack is off.
+ ** FULL_POWER: controller is in full-power state.
+ ** LOW_POWER: controller is in lower-power state.
+ **
+ *******************************************************************************/
+ enum PowerLevel {UNKNOWN_LEVEL, FULL_POWER, LOW_POWER, POWER_OFF};
+
+ /*******************************************************************************
+ **
+ ** Description: DISCOVERY: Discovery is enabled
+ ** SE_ROUTING: Routing to SE is enabled.
+ ** SE_CONNECTED: SE is connected.
+ **
+ *******************************************************************************/
+ typedef int PowerActivity;
+ static const PowerActivity DISCOVERY;
+ static const PowerActivity SE_ROUTING;
+ static const PowerActivity SE_CONNECTED;
+
+ /*******************************************************************************
+ **
+ ** Description: Platform Power Level, copied from NativeNfcBrcmPowerMode.java.
+ ** UNKNOWN_LEVEL: power level is unknown.
+ ** POWER_OFF: The phone is turned OFF
+ ** SCREEN_OFF: The phone is turned ON but screen is OFF
+ ** SCREEN_ON_LOCKED: The phone is turned ON, screen is ON but user locked
+ ** SCREEN_ON_UNLOCKED: The phone is turned ON, screen is ON, and user unlocked
+ **
+ *******************************************************************************/
+ static const int PLATFORM_UNKNOWN_LEVEL = 0;
+ static const int PLATFORM_POWER_OFF = 1;
+ static const int PLATFORM_SCREEN_OFF = 2;
+ static const int PLATFORM_SCREEN_ON_LOCKED = 3;
+ static const int PLATFORM_SCREEN_ON_UNLOCKED = 4;
+
+ static const int VBAT_MONITOR_ENABLED = 1;
+ static const int VBAT_MONITOR_PRIMARY_THRESHOLD = 5;
+ static const int VBAT_MONITOR_SECONDARY_THRESHOLD = 8;
+ /*******************************************************************************
+ **
+ ** Function: PowerSwitch
+ **
+ ** Description: Initialize member variables.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ PowerSwitch ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: ~PowerSwitch
+ **
+ ** Description: Release all resources.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ ~PowerSwitch ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: getInstance
+ **
+ ** Description: Get the singleton of this object.
+ **
+ ** Returns: Reference to this object.
+ **
+ *******************************************************************************/
+ static PowerSwitch& getInstance ();
+
+ /*******************************************************************************
+ **
+ ** Function: initialize
+ **
+ ** Description: Initialize member variables.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void initialize (PowerLevel level);
+
+
+ /*******************************************************************************
+ **
+ ** Function: getLevel
+ **
+ ** Description: Get the current power level of the controller.
+ **
+ ** Returns: Power level.
+ **
+ *******************************************************************************/
+ PowerLevel getLevel ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: setLevel
+ **
+ ** Description: Set the controller's power level.
+ ** level: power level.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool setLevel (PowerLevel level);
+
+
+ /*******************************************************************************
+ **
+ ** Function: setModeOff
+ **
+ ** Description: Set a mode to be deactive.
+ **
+ ** Returns: True if any mode is still active.
+ **
+ *******************************************************************************/
+ bool setModeOff (PowerActivity deactivated);
+
+
+ /*******************************************************************************
+ **
+ ** Function: setModeOn
+ **
+ ** Description: Set a mode to be active.
+ **
+ ** Returns: True if any mode is active.
+ **
+ *******************************************************************************/
+ bool setModeOn (PowerActivity activated);
+
+
+ /*******************************************************************************
+ **
+ ** Function: abort
+ **
+ ** Description: Abort and unblock currrent operation.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void abort ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: deviceManagementCallback
+ **
+ ** Description: Callback function for the stack.
+ ** event: event ID.
+ ** eventData: event's data.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ static void deviceManagementCallback (UINT8 event, tNFA_DM_CBACK_DATA* eventData);
+
+
+ /*******************************************************************************
+ **
+ ** Function: isPowerOffSleepFeatureEnabled
+ **
+ ** Description: Whether power-off-sleep feature is enabled in .conf file.
+ **
+ ** Returns: True if feature is enabled.
+ **
+ *******************************************************************************/
+ bool isPowerOffSleepFeatureEnabled ();
+
+private:
+ PowerLevel mCurrLevel;
+ UINT8 mCurrDeviceMgtPowerState; //device management power state; such as NFA_DM_PWR_STATE_???
+ int mDesiredScreenOffPowerState; //read from .conf file; 0=power-off-sleep; 1=full power; 2=CE4 power
+ static PowerSwitch sPowerSwitch; //singleton object
+ static const UINT8 NFA_DM_PWR_STATE_UNKNOWN = -1; //device management power state power state is unknown
+ SyncEvent mPowerStateEvent;
+ PowerActivity mCurrActivity;
+ Mutex mMutex;
+
+
+ /*******************************************************************************
+ **
+ ** Function: setPowerOffSleepState
+ **
+ ** Description: Adjust controller's power-off-sleep state.
+ ** sleep: whether to enter sleep state.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool setPowerOffSleepState (bool sleep);
+
+
+ /*******************************************************************************
+ **
+ ** Function: deviceMgtPowerStateToString
+ **
+ ** Description: Decode power level to a string.
+ ** deviceMgtPowerState: power level.
+ **
+ ** Returns: Text representation of power level.
+ **
+ *******************************************************************************/
+ const char* deviceMgtPowerStateToString (UINT8 deviceMgtPowerState);
+
+
+ /*******************************************************************************
+ **
+ ** Function: powerLevelToString
+ **
+ ** Description: Decode power level to a string.
+ ** level: power level.
+ **
+ ** Returns: Text representation of power level.
+ **
+ *******************************************************************************/
+ const char* powerLevelToString (PowerLevel level);
+};
diff --git a/nci/jni/RouteDataSet.cpp b/nci/jni/RouteDataSet.cpp
new file mode 100644
index 0000000..1458776
--- /dev/null
+++ b/nci/jni/RouteDataSet.cpp
@@ -0,0 +1,555 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+/*
+ * Import and export general routing data using a XML file.
+ */
+#include "OverrideLog.h"
+#include "RouteDataSet.h"
+#include "libxml/xmlmemory.h"
+#include <errno.h>
+#include <sys/stat.h>
+
+extern char bcm_nfc_location[];
+
+
+/*******************************************************************************
+**
+** Function: AidBuffer
+**
+** Description: Parse a string of hex numbers. Store result in an array of
+** bytes.
+** aid: string of hex numbers.
+**
+** Returns: None.
+**
+*******************************************************************************/
+AidBuffer::AidBuffer (std::string& aid)
+: mBuffer (NULL),
+ mBufferLen (0)
+{
+ unsigned int num = 0;
+ const char delimiter = ':';
+ std::string::size_type pos1 = 0;
+ std::string::size_type pos2 = aid.find_first_of (delimiter);
+
+ //parse the AID string; each hex number is separated by a colon;
+ mBuffer = new UINT8 [aid.length()];
+ while (true)
+ {
+ num = 0;
+ if (pos2 == std::string::npos)
+ {
+ sscanf (aid.substr(pos1).c_str(), "%x", &num);
+ mBuffer [mBufferLen] = (UINT8) num;
+ mBufferLen++;
+ break;
+ }
+ else
+ {
+ sscanf (aid.substr(pos1, pos2-pos1+1).c_str(), "%x", &num);
+ mBuffer [mBufferLen] = (UINT8) num;
+ mBufferLen++;
+ pos1 = pos2 + 1;
+ pos2 = aid.find_first_of (delimiter, pos1);
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: ~AidBuffer
+**
+** Description: Release all resources.
+**
+** Returns: None.
+**
+*******************************************************************************/
+AidBuffer::~AidBuffer ()
+{
+ delete [] mBuffer;
+}
+
+
+/*******************************************************************************/
+/*******************************************************************************/
+
+
+const char* RouteDataSet::sConfigFile = "/param/route.xml";
+
+
+/*******************************************************************************
+**
+** Function: ~RouteDataSet
+**
+** Description: Release all resources.
+**
+** Returns: None.
+**
+*******************************************************************************/
+RouteDataSet::~RouteDataSet ()
+{
+ deleteDatabase ();
+}
+
+
+/*******************************************************************************
+**
+** Function: initialize
+**
+** Description: Initialize resources.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool RouteDataSet::initialize ()
+{
+ static const char fn [] = "RouteDataSet::initialize";
+ ALOGD ("%s: enter", fn);
+ //check that the libxml2 version in use is compatible
+ //with the version the software has been compiled with
+ LIBXML_TEST_VERSION
+ ALOGD ("%s: exit; return=true", fn);
+ return true;
+}
+
+
+/*******************************************************************************
+**
+** Function: deleteDatabase
+**
+** Description: Delete all routes stored in all databases.
+**
+** Returns: None.
+**
+*******************************************************************************/
+void RouteDataSet::deleteDatabase ()
+{
+ static const char fn [] = "RouteDataSet::deleteDatabase";
+ ALOGD ("%s: default db size=%u; sec elem db size=%u", fn, mDefaultRouteDatabase.size(), mSecElemRouteDatabase.size());
+ Database::iterator it;
+
+ for (it = mDefaultRouteDatabase.begin(); it != mDefaultRouteDatabase.end(); it++)
+ delete (*it);
+ mDefaultRouteDatabase.clear ();
+
+ for (it = mSecElemRouteDatabase.begin(); it != mSecElemRouteDatabase.end(); it++)
+ delete (*it);
+ mSecElemRouteDatabase.clear ();
+}
+
+
+/*******************************************************************************
+**
+** Function: import
+**
+** Description: Import data from an XML file. Fill the databases.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool RouteDataSet::import ()
+{
+ static const char fn [] = "RouteDataSet::import";
+ ALOGD ("%s: enter", fn);
+ bool retval = false;
+ xmlDocPtr doc;
+ xmlNodePtr node1;
+ std::string strFilename(bcm_nfc_location);
+ strFilename += sConfigFile;
+
+ deleteDatabase ();
+
+ doc = xmlParseFile (strFilename.c_str());
+ if (doc == NULL)
+ {
+ ALOGD ("%s: fail parse", fn);
+ goto TheEnd;
+ }
+
+ node1 = xmlDocGetRootElement (doc);
+ if (node1 == NULL)
+ {
+ ALOGE ("%s: fail root element", fn);
+ goto TheEnd;
+ }
+ ALOGD ("%s: root=%s", fn, node1->name);
+
+ node1 = node1->xmlChildrenNode;
+ while (node1) //loop through all elements in <Routes ...
+ {
+ if (xmlStrcmp(node1->name, (const xmlChar*) "Route")==0)
+ {
+ xmlChar* value = xmlGetProp (node1, (const xmlChar*) "Type");
+ if (value && (xmlStrcmp (value, (const xmlChar*) "SecElemSelectedRoutes") == 0))
+ {
+ ALOGD ("%s: found SecElemSelectedRoutes", fn);
+ xmlNodePtr node2 = node1->xmlChildrenNode;
+ while (node2) //loop all elements in <Route Type="SecElemSelectedRoutes" ...
+ {
+ if (xmlStrcmp(node2->name, (const xmlChar*) "Proto")==0)
+ importProtocolRoute (node2, mSecElemRouteDatabase);
+ else if (xmlStrcmp(node2->name, (const xmlChar*) "Tech")==0)
+ importTechnologyRoute (node2, mSecElemRouteDatabase);
+ node2 = node2->next;
+ } //loop all elements in <Route Type="SecElemSelectedRoutes" ...
+ }
+ else if (value && (xmlStrcmp (value, (const xmlChar*) "DefaultRoutes") == 0))
+ {
+ ALOGD ("%s: found DefaultRoutes", fn);
+ xmlNodePtr node2 = node1->xmlChildrenNode;
+ while (node2) //loop all elements in <Route Type="DefaultRoutes" ...
+ {
+ if (xmlStrcmp(node2->name, (const xmlChar*) "Proto")==0)
+ importProtocolRoute (node2, mDefaultRouteDatabase);
+ else if (xmlStrcmp(node2->name, (const xmlChar*) "Tech")==0)
+ importTechnologyRoute (node2, mDefaultRouteDatabase);
+ node2 = node2->next;
+ } //loop all elements in <Route Type="DefaultRoutes" ...
+ }
+ if (value)
+ xmlFree (value);
+ } //check <Route ...
+ node1 = node1->next;
+ } //loop through all elements in <Routes ...
+ retval = true;
+
+TheEnd:
+ xmlFreeDoc (doc);
+ xmlCleanupParser ();
+ ALOGD ("%s: exit; return=%u", fn, retval);
+ return retval;
+}
+
+
+/*******************************************************************************
+**
+** Function: saveToFile
+**
+** Description: Save XML data from a string into a file.
+** routesXml: XML that represents routes.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool RouteDataSet::saveToFile (const char* routesXml)
+{
+ static const char fn [] = "RouteDataSet::saveToFile";
+ FILE* fh = NULL;
+ size_t actualWritten = 0;
+ bool retval = false;
+ std::string filename (bcm_nfc_location);
+
+ filename.append (sConfigFile);
+ fh = fopen (filename.c_str (), "w");
+ if (fh == NULL)
+ {
+ ALOGE ("%s: fail to open file", fn);
+ return false;
+ }
+
+ actualWritten = fwrite (routesXml, sizeof(char), strlen(routesXml), fh);
+ retval = actualWritten == strlen(routesXml);
+ fclose (fh);
+ ALOGD ("%s: wrote %u bytes", fn, actualWritten);
+ if (retval == false)
+ ALOGE ("%s: error during write", fn);
+
+ //set file permission to
+ //owner read, write; group read; other read
+ chmod (filename.c_str (), S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ return retval;
+}
+
+
+/*******************************************************************************
+**
+** Function: loadFromFile
+**
+** Description: Load XML data from file into a string.
+** routesXml: string to receive XML data.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool RouteDataSet::loadFromFile (std::string& routesXml)
+{
+ static const char fn [] = "RouteDataSet::loadFromFile";
+ FILE* fh = NULL;
+ size_t actual = 0;
+ char buffer [1024];
+ std::string filename (bcm_nfc_location);
+
+ filename.append (sConfigFile);
+ fh = fopen (filename.c_str (), "r");
+ if (fh == NULL)
+ {
+ ALOGD ("%s: fail to open file", fn);
+ return false;
+ }
+
+ while (true)
+ {
+ actual = fread (buffer, sizeof(char), sizeof(buffer), fh);
+ if (actual == 0)
+ break;
+ routesXml.append (buffer, actual);
+ }
+ fclose (fh);
+ ALOGD ("%s: read %u bytes", fn, routesXml.length());
+ return true;
+}
+
+
+
+
+/*******************************************************************************
+**
+** Function: importProtocolRoute
+**
+** Description: Parse data for protocol routes.
+** element: XML node for one protocol route.
+** database: store data in this database.
+**
+** Returns: None.
+**
+*******************************************************************************/
+void RouteDataSet::importProtocolRoute (xmlNodePtr& element, Database& database)
+{
+ static const char fn [] = "RouteDataSet::importProtocolRoute";
+ const xmlChar* id = (const xmlChar*) "Id";
+ const xmlChar* secElem = (const xmlChar*) "SecElem";
+ const xmlChar* trueString = (const xmlChar*) "true";
+ const xmlChar* switchOn = (const xmlChar*) "SwitchOn";
+ const xmlChar* switchOff = (const xmlChar*) "SwitchOff";
+ const xmlChar* batteryOff = (const xmlChar*) "BatteryOff";
+ RouteDataForProtocol* data = new RouteDataForProtocol;
+ xmlChar* value = NULL;
+
+ ALOGD_IF (sDebug, "%s: element=%s", fn, element->name);
+ value = xmlGetProp (element, id);
+ if (value)
+ {
+ if (xmlStrcmp (value, (const xmlChar*) "T1T") == 0)
+ data->mProtocol = NFA_PROTOCOL_MASK_T1T;
+ else if (xmlStrcmp (value, (const xmlChar*) "T2T") == 0)
+ data->mProtocol = NFA_PROTOCOL_MASK_T2T;
+ else if (xmlStrcmp (value, (const xmlChar*) "T3T") == 0)
+ data->mProtocol = NFA_PROTOCOL_MASK_T3T;
+ else if (xmlStrcmp (value, (const xmlChar*) "IsoDep") == 0)
+ data->mProtocol = NFA_PROTOCOL_MASK_ISO_DEP;
+ xmlFree (value);
+ ALOGD_IF (sDebug, "%s: %s=0x%X", fn, id, data->mProtocol);
+ }
+
+ value = xmlGetProp (element, secElem);
+ if (value)
+ {
+ data->mNfaEeHandle = strtol ((char*) value, NULL, 16);
+ xmlFree (value);
+ data->mNfaEeHandle = data->mNfaEeHandle | NFA_HANDLE_GROUP_EE;
+ ALOGD_IF (sDebug, "%s: %s=0x%X", fn, secElem, data->mNfaEeHandle);
+ }
+
+ value = xmlGetProp (element, switchOn);
+ if (value)
+ {
+ data->mSwitchOn = (xmlStrcmp (value, trueString) == 0);
+ xmlFree (value);
+ }
+
+ value = xmlGetProp (element, switchOff);
+ if (value)
+ {
+ data->mSwitchOff = (xmlStrcmp (value, trueString) == 0);
+ xmlFree (value);
+ }
+
+ value = xmlGetProp (element, batteryOff);
+ if (value)
+ {
+ data->mBatteryOff = (xmlStrcmp (value, trueString) == 0);
+ xmlFree (value);
+ }
+ database.push_back (data);
+}
+
+
+/*******************************************************************************
+**
+** Function: importTechnologyRoute
+**
+** Description: Parse data for technology routes.
+** element: XML node for one technology route.
+** database: store data in this database.
+**
+** Returns: None.
+**
+*******************************************************************************/
+void RouteDataSet::importTechnologyRoute (xmlNodePtr& element, Database& database)
+{
+ static const char fn [] = "RouteDataSet::importTechnologyRoute";
+ const xmlChar* id = (const xmlChar*) "Id";
+ const xmlChar* secElem = (const xmlChar*) "SecElem";
+ const xmlChar* trueString = (const xmlChar*) "true";
+ const xmlChar* switchOn = (const xmlChar*) "SwitchOn";
+ const xmlChar* switchOff = (const xmlChar*) "SwitchOff";
+ const xmlChar* batteryOff = (const xmlChar*) "BatteryOff";
+ RouteDataForTechnology* data = new RouteDataForTechnology;
+ xmlChar* value = NULL;
+
+ ALOGD_IF (sDebug, "%s: element=%s", fn, element->name);
+ value = xmlGetProp (element, id);
+ if (value)
+ {
+ if (xmlStrcmp (value, (const xmlChar*) "NfcA") == 0)
+ data->mTechnology = NFA_TECHNOLOGY_MASK_A;
+ else if (xmlStrcmp (value, (const xmlChar*) "NfcB") == 0)
+ data->mTechnology = NFA_TECHNOLOGY_MASK_B;
+ else if (xmlStrcmp (value, (const xmlChar*) "NfcF") == 0)
+ data->mTechnology = NFA_TECHNOLOGY_MASK_F;
+ xmlFree (value);
+ ALOGD_IF (sDebug, "%s: %s=0x%X", fn, id, data->mTechnology);
+ }
+
+ value = xmlGetProp (element, secElem);
+ if (value)
+ {
+ data->mNfaEeHandle = strtol ((char*) value, NULL, 16);
+ xmlFree (value);
+ data->mNfaEeHandle = data->mNfaEeHandle | NFA_HANDLE_GROUP_EE;
+ ALOGD_IF (sDebug, "%s: %s=0x%X", fn, secElem, data->mNfaEeHandle);
+ }
+
+ value = xmlGetProp (element, switchOn);
+ if (value)
+ {
+ data->mSwitchOn = (xmlStrcmp (value, trueString) == 0);
+ xmlFree (value);
+ }
+
+ value = xmlGetProp (element, switchOff);
+ if (value)
+ {
+ data->mSwitchOff = (xmlStrcmp (value, trueString) == 0);
+ xmlFree (value);
+ }
+
+ value = xmlGetProp (element, batteryOff);
+ if (value)
+ {
+ data->mBatteryOff = (xmlStrcmp (value, trueString) == 0);
+ xmlFree (value);
+ }
+ database.push_back (data);
+}
+
+
+/*******************************************************************************
+**
+** Function: deleteFile
+**
+** Description: Delete route data XML file.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool RouteDataSet::deleteFile ()
+{
+ static const char fn [] = "RouteDataSet::deleteFile";
+ std::string filename (bcm_nfc_location);
+ filename.append (sConfigFile);
+ int stat = remove (filename.c_str());
+ ALOGD ("%s: exit %u", fn, stat==0);
+ return stat == 0;
+}
+
+
+/*******************************************************************************
+**
+** Function: getDatabase
+**
+** Description: Obtain a database of routing data.
+** selection: which database.
+**
+** Returns: Pointer to database.
+**
+*******************************************************************************/
+RouteDataSet::Database* RouteDataSet::getDatabase (DatabaseSelection selection)
+{
+ switch (selection)
+ {
+ case DefaultRouteDatabase:
+ return &mDefaultRouteDatabase;
+ case SecElemRouteDatabase:
+ return &mSecElemRouteDatabase;
+ }
+ return NULL;
+}
+
+
+/*******************************************************************************
+**
+** Function: printDiagnostic
+**
+** Description: Print some diagnostic output.
+**
+** Returns: None.
+**
+*******************************************************************************/
+void RouteDataSet::printDiagnostic ()
+{
+ static const char fn [] = "RouteDataSet::printDiagnostic";
+ Database* db = getDatabase (DefaultRouteDatabase);
+
+ ALOGD ("%s: default route database", fn);
+ for (Database::iterator iter = db->begin(); iter != db->end(); iter++)
+ {
+ RouteData* routeData = *iter;
+ switch (routeData->mRouteType)
+ {
+ case RouteData::ProtocolRoute:
+ {
+ RouteDataForProtocol* proto = (RouteDataForProtocol*) routeData;
+ ALOGD ("%s: ee h=0x%X; protocol=0x%X", fn, proto->mNfaEeHandle, proto->mProtocol);
+ }
+ break;
+ }
+ }
+
+ ALOGD ("%s: sec elem route database", fn);
+ db = getDatabase (SecElemRouteDatabase);
+ for (Database::iterator iter2 = db->begin(); iter2 != db->end(); iter2++)
+ {
+ RouteData* routeData = *iter2;
+ switch (routeData->mRouteType)
+ {
+ case RouteData::ProtocolRoute:
+ {
+ RouteDataForProtocol* proto = (RouteDataForProtocol*) routeData;
+ ALOGD ("%s: ee h=0x%X; protocol=0x%X", fn, proto->mNfaEeHandle, proto->mProtocol);
+ }
+ break;
+ case RouteData::TechnologyRoute:
+ {
+ RouteDataForTechnology* tech = (RouteDataForTechnology*) routeData;
+ ALOGD ("%s: ee h=0x%X; technology=0x%X", fn, tech->mNfaEeHandle, tech->mTechnology);
+ }
+ break;
+ }
+ }
+}
diff --git a/nci/jni/RouteDataSet.h b/nci/jni/RouteDataSet.h
new file mode 100644
index 0000000..d2a09b8
--- /dev/null
+++ b/nci/jni/RouteDataSet.h
@@ -0,0 +1,308 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+/*
+ * Import and export general routing data using a XML file.
+ */
+#pragma once
+#include "NfcJniUtil.h"
+#include "nfa_api.h"
+#include <libxml/parser.h>
+#include <vector>
+#include <string>
+
+
+/*****************************************************************************
+**
+** Name: RouteData
+**
+** Description: Base class for every kind of route data.
+**
+*****************************************************************************/
+class RouteData
+{
+public:
+ enum RouteType {ProtocolRoute, TechnologyRoute};
+ RouteType mRouteType;
+
+protected:
+ RouteData (RouteType routeType) : mRouteType (routeType)
+ {}
+};
+
+
+
+
+/*****************************************************************************
+**
+** Name: RouteDataForProtocol
+**
+** Description: Data for protocol routes.
+**
+*****************************************************************************/
+class RouteDataForProtocol : public RouteData
+{
+public:
+ int mNfaEeHandle; //for example 0x4f3, 0x4f4
+ bool mSwitchOn;
+ bool mSwitchOff;
+ bool mBatteryOff;
+ tNFA_PROTOCOL_MASK mProtocol;
+
+ RouteDataForProtocol () : RouteData (ProtocolRoute), mNfaEeHandle (NFA_HANDLE_INVALID),
+ mSwitchOn (false), mSwitchOff (false), mBatteryOff (false),
+ mProtocol (0)
+ {}
+};
+
+
+/*****************************************************************************
+**
+** Name: RouteDataForTechnology
+**
+** Description: Data for technology routes.
+**
+*****************************************************************************/
+class RouteDataForTechnology : public RouteData
+{
+public:
+ int mNfaEeHandle; //for example 0x4f3, 0x4f4
+ bool mSwitchOn;
+ bool mSwitchOff;
+ bool mBatteryOff;
+ tNFA_TECHNOLOGY_MASK mTechnology;
+
+ RouteDataForTechnology () : RouteData (TechnologyRoute), mNfaEeHandle (NFA_HANDLE_INVALID),
+ mSwitchOn (false), mSwitchOff (false), mBatteryOff (false),
+ mTechnology (0)
+ {}
+};
+
+
+/*****************************************************************************/
+/*****************************************************************************/
+
+
+/*****************************************************************************
+**
+** Name: AidBuffer
+**
+** Description: Buffer to store AID after converting a string of hex
+** values to bytes.
+**
+*****************************************************************************/
+class AidBuffer
+{
+public:
+
+ /*******************************************************************************
+ **
+ ** Function: AidBuffer
+ **
+ ** Description: Parse a string of hex numbers. Store result in an array of
+ ** bytes.
+ ** aid: string of hex numbers.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ AidBuffer (std::string& aid);
+
+
+ /*******************************************************************************
+ **
+ ** Function: ~AidBuffer
+ **
+ ** Description: Release all resources.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ ~AidBuffer ();
+
+
+ UINT8* buffer () {return mBuffer;};
+ int length () {return mBufferLen;};
+
+private:
+ UINT8* mBuffer;
+ UINT32 mBufferLen;
+};
+
+
+/*****************************************************************************/
+/*****************************************************************************/
+
+
+/*****************************************************************************
+**
+** Name: RouteDataSet
+**
+** Description: Import and export general routing data using a XML file.
+** See /data/bcm/param/route.xml
+**
+*****************************************************************************/
+class RouteDataSet
+{
+public:
+ typedef std::vector<RouteData*> Database;
+ enum DatabaseSelection {DefaultRouteDatabase, SecElemRouteDatabase};
+
+
+ /*******************************************************************************
+ **
+ ** Function: ~RouteDataSet
+ **
+ ** Description: Release all resources.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ ~RouteDataSet ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: initialize
+ **
+ ** Description: Initialize resources.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool initialize ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: import
+ **
+ ** Description: Import data from an XML file. Fill the database.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool import ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: getDatabase
+ **
+ ** Description: Obtain a database of routing data.
+ ** selection: which database.
+ **
+ ** Returns: Pointer to database.
+ **
+ *******************************************************************************/
+ Database* getDatabase (DatabaseSelection selection);
+
+
+ /*******************************************************************************
+ **
+ ** Function: saveToFile
+ **
+ ** Description: Save XML data from a string into a file.
+ ** routesXml: XML that represents routes.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ static bool saveToFile (const char* routesXml);
+
+
+ /*******************************************************************************
+ **
+ ** Function: loadFromFile
+ **
+ ** Description: Load XML data from file into a string.
+ ** routesXml: string to receive XML data.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ static bool loadFromFile (std::string& routesXml);
+
+
+ /*******************************************************************************
+ **
+ ** Function: deleteFile
+ **
+ ** Description: Delete route data XML file.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ static bool deleteFile ();
+
+ /*******************************************************************************
+ **
+ ** Function: printDiagnostic
+ **
+ ** Description: Print some diagnostic output.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ void printDiagnostic ();
+
+private:
+ Database mSecElemRouteDatabase; //routes when NFC service selects sec elem
+ Database mDefaultRouteDatabase; //routes when NFC service deselects sec elem
+ static const char* sConfigFile;
+ static const bool sDebug = false;
+
+
+ /*******************************************************************************
+ **
+ ** Function: deleteDatabase
+ **
+ ** Description: Delete all routes stored in all databases.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ void deleteDatabase ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: importProtocolRoute
+ **
+ ** Description: Parse data for protocol routes.
+ ** element: XML node for one protocol route.
+ ** database: store data in this database.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ void importProtocolRoute (xmlNodePtr& element, Database& database);
+
+
+ /*******************************************************************************
+ **
+ ** Function: importTechnologyRoute
+ **
+ ** Description: Parse data for technology routes.
+ ** element: XML node for one technology route.
+ ** database: store data in this database.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ void importTechnologyRoute (xmlNodePtr& element, Database& database);
+};
+
diff --git a/nci/jni/SecureElement.cpp b/nci/jni/SecureElement.cpp
new file mode 100755
index 0000000..3c9256b
--- /dev/null
+++ b/nci/jni/SecureElement.cpp
@@ -0,0 +1,2189 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+/*
+ * Communicate with secure elements that are attached to the NFC
+ * controller.
+ */
+#include <semaphore.h>
+#include <errno.h>
+#include "OverrideLog.h"
+#include "SecureElement.h"
+#include "config.h"
+#include "PowerSwitch.h"
+#include "HostAidRouter.h"
+#include "JavaClassConstants.h"
+
+
+/*****************************************************************************
+**
+** public variables
+**
+*****************************************************************************/
+int gSEId = -1; // secure element ID to use in connectEE(), -1 means not set
+int gGatePipe = -1; // gate id or static pipe id to use in connectEE(), -1 means not set
+bool gUseStaticPipe = false; // if true, use gGatePipe as static pipe id. if false, use as gate id
+
+namespace android
+{
+ extern void startRfDiscovery (bool isStart);
+}
+
+//////////////////////////////////////////////
+//////////////////////////////////////////////
+
+
+SecureElement SecureElement::sSecElem;
+const char* SecureElement::APP_NAME = "nfc_jni";
+
+
+/*******************************************************************************
+**
+** Function: SecureElement
+**
+** Description: Initialize member variables.
+**
+** Returns: None
+**
+*******************************************************************************/
+SecureElement::SecureElement ()
+: mActiveEeHandle (NFA_HANDLE_INVALID),
+ mDestinationGate (4), //loopback gate
+ mNfaHciHandle (NFA_HANDLE_INVALID),
+ mNativeData (NULL),
+ mIsInit (false),
+ mActualNumEe (0),
+ mNumEePresent(0),
+ mbNewEE (true), // by default we start w/thinking there are new EE
+ mNewPipeId (0),
+ mNewSourceGate (0),
+ mActiveSeOverride(0),
+ mCommandStatus (NFA_STATUS_OK),
+ mIsPiping (false),
+ mCurrentRouteSelection (NoRoute),
+ mActualResponseSize(0),
+ mUseOberthurWarmReset (false),
+ mActivatedInListenMode (false),
+ mOberthurWarmResetCommand (3),
+ mRfFieldIsOn(false)
+{
+ memset (&mEeInfo, 0, sizeof(mEeInfo));
+ memset (&mUiccInfo, 0, sizeof(mUiccInfo));
+ memset (&mHciCfg, 0, sizeof(mHciCfg));
+ memset (mResponseData, 0, sizeof(mResponseData));
+ memset (mAidForEmptySelect, 0, sizeof(mAidForEmptySelect));
+ memset (&mLastRfFieldToggle, 0, sizeof(mLastRfFieldToggle));
+}
+
+
+/*******************************************************************************
+**
+** Function: ~SecureElement
+**
+** Description: Release all resources.
+**
+** Returns: None
+**
+*******************************************************************************/
+SecureElement::~SecureElement ()
+{
+}
+
+
+/*******************************************************************************
+**
+** Function: getInstance
+**
+** Description: Get the SecureElement singleton object.
+**
+** Returns: SecureElement object.
+**
+*******************************************************************************/
+SecureElement& SecureElement::getInstance()
+{
+ return sSecElem;
+}
+
+
+/*******************************************************************************
+**
+** Function: setActiveSeOverride
+**
+** Description: Specify which secure element to turn on.
+** activeSeOverride: ID of secure element
+**
+** Returns: None
+**
+*******************************************************************************/
+void SecureElement::setActiveSeOverride(UINT8 activeSeOverride)
+{
+ ALOGD ("SecureElement::setActiveSeOverride, seid=0x%X", activeSeOverride);
+ mActiveSeOverride = activeSeOverride;
+}
+
+
+/*******************************************************************************
+**
+** Function: initialize
+**
+** Description: Initialize all member variables.
+** native: Native data.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool SecureElement::initialize (nfc_jni_native_data* native)
+{
+ static const char fn [] = "SecureElement::initialize";
+ tNFA_STATUS nfaStat;
+ UINT8 xx = 0, yy = 0;
+ unsigned long num = 0;
+
+ ALOGD ("%s: enter", fn);
+
+ if (GetNumValue("NFA_HCI_DEFAULT_DEST_GATE", &num, sizeof(num)))
+ mDestinationGate = num;
+ ALOGD ("%s: Default destination gate: %d", fn, mDestinationGate);
+
+ // active SE, if not set active all SEs
+ if (GetNumValue("ACTIVE_SE", &num, sizeof(num)))
+ mActiveSeOverride = num;
+ ALOGD ("%s: Active SE override: %d", fn, mActiveSeOverride);
+
+ if (GetNumValue("OBERTHUR_WARM_RESET_COMMAND", &num, sizeof(num)))
+ {
+ mUseOberthurWarmReset = true;
+ mOberthurWarmResetCommand = (UINT8) num;
+ }
+
+ mActiveEeHandle = NFA_HANDLE_INVALID;
+ mNfaHciHandle = NFA_HANDLE_INVALID;
+
+ mNativeData = native;
+ mActualNumEe = MAX_NUM_EE;
+ mbNewEE = true;
+ mNewPipeId = 0;
+ mNewSourceGate = 0;
+ mCurrentRouteSelection = NoRoute;
+ memset (mEeInfo, 0, sizeof(mEeInfo));
+ memset (&mUiccInfo, 0, sizeof(mUiccInfo));
+ memset (&mHciCfg, 0, sizeof(mHciCfg));
+ mUsedAids.clear ();
+ memset(mAidForEmptySelect, 0, sizeof(mAidForEmptySelect));
+
+ // Get Fresh EE info.
+ if (! getEeInfo())
+ return (false);
+
+ {
+ SyncEventGuard guard (mEeRegisterEvent);
+ ALOGD ("%s: try ee register", fn);
+ nfaStat = NFA_EeRegister (nfaEeCallback);
+ if (nfaStat != NFA_STATUS_OK)
+ {
+ ALOGE ("%s: fail ee register; error=0x%X", fn, nfaStat);
+ return (false);
+ }
+ mEeRegisterEvent.wait ();
+ }
+
+ // If the controller has an HCI Network, register for that
+ for (xx = 0; xx < mActualNumEe; xx++)
+ {
+ if ((mEeInfo[xx].num_interface > 0) && (mEeInfo[xx].ee_interface[0] == NCI_NFCEE_INTERFACE_HCI_ACCESS) )
+ {
+ ALOGD ("%s: Found HCI network, try hci register", fn);
+
+ SyncEventGuard guard (mHciRegisterEvent);
+
+ nfaStat = NFA_HciRegister (const_cast<char*>(APP_NAME), nfaHciCallback, TRUE);
+ if (nfaStat != NFA_STATUS_OK)
+ {
+ ALOGE ("%s: fail hci register; error=0x%X", fn, nfaStat);
+ return (false);
+ }
+ mHciRegisterEvent.wait();
+ break;
+ }
+ }
+
+ mRouteDataSet.initialize ();
+ mRouteDataSet.import (); //read XML file
+ HostAidRouter::getInstance().initialize ();
+
+ GetStrValue(NAME_AID_FOR_EMPTY_SELECT, (char*)&mAidForEmptySelect[0], sizeof(mAidForEmptySelect));
+
+ mIsInit = true;
+ ALOGD ("%s: exit", fn);
+ return (true);
+}
+
+
+/*******************************************************************************
+**
+** Function: finalize
+**
+** Description: Release all resources.
+**
+** Returns: None
+**
+*******************************************************************************/
+void SecureElement::finalize ()
+{
+ static const char fn [] = "SecureElement::finalize";
+ ALOGD ("%s: enter", fn);
+ tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
+
+ NFA_EeDeregister (nfaEeCallback);
+
+ if (mNfaHciHandle != NFA_HANDLE_INVALID)
+ NFA_HciDeregister (const_cast<char*>(APP_NAME));
+
+ mNfaHciHandle = NFA_HANDLE_INVALID;
+ mNativeData = NULL;
+ mIsInit = false;
+ mActualNumEe = 0;
+ mNumEePresent = 0;
+ mNewPipeId = 0;
+ mNewSourceGate = 0;
+ mIsPiping = false;
+ memset (mEeInfo, 0, sizeof(mEeInfo));
+ memset (&mUiccInfo, 0, sizeof(mUiccInfo));
+
+ ALOGD ("%s: exit", fn);
+}
+
+
+/*******************************************************************************
+**
+** Function: getEeInfo
+**
+** Description: Get latest information about execution environments from stack.
+**
+** Returns: True if at least 1 EE is available.
+**
+*******************************************************************************/
+bool SecureElement::getEeInfo()
+{
+ static const char fn [] = "SecureElement::getEeInfo";
+ ALOGD ("%s: enter; mbNewEE=%d, mActualNumEe=%d", fn, mbNewEE, mActualNumEe);
+ tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
+ UINT8 xx = 0, yy = 0;
+
+ // If mbNewEE is true then there is new EE info.
+ if (mbNewEE)
+ {
+ mActualNumEe = MAX_NUM_EE;
+
+ if ((nfaStat = NFA_EeGetInfo (&mActualNumEe, mEeInfo)) != NFA_STATUS_OK)
+ {
+ ALOGE ("%s: fail get info; error=0x%X", fn, nfaStat);
+ mActualNumEe = 0;
+ }
+ else
+ {
+ mbNewEE = false;
+
+ ALOGD ("%s: num EEs discovered: %u", fn, mActualNumEe);
+ if (mActualNumEe != 0)
+ {
+ for (UINT8 xx = 0; xx < mActualNumEe; xx++)
+ {
+ if ((mEeInfo[xx].num_interface != 0) && (mEeInfo[xx].ee_interface[0] != NCI_NFCEE_INTERFACE_HCI_ACCESS) )
+ mNumEePresent++;
+
+ ALOGD ("%s: EE[%u] Handle: 0x%04x Status: %s Num I/f: %u: (0x%02x, 0x%02x) Num TLVs: %u",
+ fn, xx, mEeInfo[xx].ee_handle, eeStatusToString(mEeInfo[xx].ee_status), mEeInfo[xx].num_interface,
+ mEeInfo[xx].ee_interface[0], mEeInfo[xx].ee_interface[1], mEeInfo[xx].num_tlvs);
+
+ for (yy = 0; yy < mEeInfo[xx].num_tlvs; yy++)
+ {
+ ALOGD ("%s: EE[%u] TLV[%u] Tag: 0x%02x Len: %u Values[]: 0x%02x 0x%02x 0x%02x ...",
+ fn, xx, yy, mEeInfo[xx].ee_tlv[yy].tag, mEeInfo[xx].ee_tlv[yy].len, mEeInfo[xx].ee_tlv[yy].info[0],
+ mEeInfo[xx].ee_tlv[yy].info[1], mEeInfo[xx].ee_tlv[yy].info[2]);
+ }
+ }
+ }
+ }
+ }
+ ALOGD ("%s: exit; mActualNumEe=%d, mNumEePresent=%d", fn, mActualNumEe,mNumEePresent);
+ return (mActualNumEe != 0);
+}
+
+
+/*******************************************************************************
+**
+** Function TimeDiff
+**
+** Description Computes time difference in milliseconds.
+**
+** Returns Time difference in milliseconds
+**
+*******************************************************************************/
+static UINT32 TimeDiff(timespec start, timespec end)
+{
+ end.tv_sec -= start.tv_sec;
+ end.tv_nsec -= start.tv_nsec;
+
+ if (end.tv_nsec < 0) {
+ end.tv_nsec += 10e8;
+ end.tv_sec -=1;
+ }
+
+ return (end.tv_sec * 1000) + (end.tv_nsec / 10e5);
+}
+
+/*******************************************************************************
+**
+** Function: isRfFieldOn
+**
+** Description: Can be used to determine if the SE is in an RF field
+**
+** Returns: True if the SE is activated in an RF field
+**
+*******************************************************************************/
+bool SecureElement::isRfFieldOn() {
+ AutoMutex mutex(mMutex);
+ if (mRfFieldIsOn) {
+ return true;
+ }
+ struct timespec now;
+ int ret = clock_gettime(CLOCK_MONOTONIC, &now);
+ if (ret == -1) {
+ ALOGE("isRfFieldOn(): clock_gettime failed");
+ return false;
+ }
+ if (TimeDiff(mLastRfFieldToggle, now) < 50) {
+ // If it was less than 50ms ago that RF field
+ // was turned off, still return ON.
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/*******************************************************************************
+**
+** Function: isActivatedInListenMode
+**
+** Description: Can be used to determine if the SE is activated in listen mode
+**
+** Returns: True if the SE is activated in listen mode
+**
+*******************************************************************************/
+bool SecureElement::isActivatedInListenMode() {
+ return mActivatedInListenMode;
+}
+
+/*******************************************************************************
+**
+** Function: getListOfEeHandles
+**
+** Description: Get the list of handles of all execution environments.
+** e: Java Virtual Machine.
+**
+** Returns: List of handles of all execution environments.
+**
+*******************************************************************************/
+jintArray SecureElement::getListOfEeHandles (JNIEnv* e)
+{
+ static const char fn [] = "SecureElement::getListOfEeHandles";
+ ALOGD ("%s: enter", fn);
+ if (mNumEePresent == 0)
+ return NULL;
+ jintArray list = NULL;
+
+ if (!mIsInit)
+ {
+ ALOGE ("%s: not init", fn);
+ return (NULL);
+ }
+
+ // Get Fresh EE info.
+ if (! getEeInfo())
+ return (NULL);
+
+ list = e->NewIntArray (mNumEePresent); //allocate array
+ jint jj = 0;
+ int cnt = 0;
+ for (int ii = 0; ii < mActualNumEe && cnt < mNumEePresent; ii++)
+ {
+ ALOGD ("%s: %u = 0x%X", fn, ii, mEeInfo[ii].ee_handle);
+ if ((mEeInfo[ii].num_interface == 0) || (mEeInfo[ii].ee_interface[0] == NCI_NFCEE_INTERFACE_HCI_ACCESS) )
+ {
+ continue;
+ }
+
+ jj = mEeInfo[ii].ee_handle & ~NFA_HANDLE_GROUP_EE;
+ e->SetIntArrayRegion (list, cnt++, 1, &jj);
+ }
+ //e->DeleteLocalRef (list);
+
+ ALOGD("%s: exit", fn);
+ return list;
+}
+
+
+/*******************************************************************************
+**
+** Function: activate
+**
+** Description: Turn on the secure element.
+** seID: ID of secure element.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool SecureElement::activate (jint seID)
+{
+ static const char fn [] = "SecureElement::activate";
+ tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
+ int numActivatedEe = 0;
+
+ ALOGD ("%s: enter; seID=0x%X", fn, seID);
+
+ if (!mIsInit)
+ {
+ ALOGE ("%s: not init", fn);
+ return false;
+ }
+
+ if (mActiveEeHandle != NFA_HANDLE_INVALID)
+ {
+ ALOGD ("%s: already active", fn);
+ return true;
+ }
+
+ // Get Fresh EE info if needed.
+ if (! getEeInfo())
+ {
+ ALOGE ("%s: no EE info", fn);
+ return false;
+ }
+
+ mActiveEeHandle = getDefaultEeHandle();
+ ALOGD ("%s: active ee h=0x%X, override se=0x%X", fn, mActiveEeHandle, mActiveSeOverride);
+ if (mActiveEeHandle == NFA_HANDLE_INVALID)
+ {
+ ALOGE ("%s: ee not found", fn);
+ return false;
+ }
+
+ UINT16 override_se = 0;
+ if (mActiveSeOverride)
+ override_se = NFA_HANDLE_GROUP_EE | mActiveSeOverride;
+
+ if (mRfFieldIsOn) {
+ ALOGE("%s: RF field indication still on, resetting", fn);
+ mRfFieldIsOn = false;
+ }
+
+ ALOGD ("%s: override seid=0x%X", fn, override_se );
+ //activate every discovered secure element
+ for (int index=0; index < mActualNumEe; index++)
+ {
+ tNFA_EE_INFO& eeItem = mEeInfo[index];
+
+ if ((eeItem.ee_handle == EE_HANDLE_0xF3) || (eeItem.ee_handle == EE_HANDLE_0xF4))
+ {
+ if (override_se && (override_se != eeItem.ee_handle) )
+ continue; // do not enable all SEs; only the override one
+
+ if (eeItem.ee_status != NFC_NFCEE_STATUS_INACTIVE)
+ {
+ ALOGD ("%s: h=0x%X already activated", fn, eeItem.ee_handle);
+ numActivatedEe++;
+ continue;
+ }
+
+ {
+ SyncEventGuard guard (mEeSetModeEvent);
+ ALOGD ("%s: set EE mode activate; h=0x%X", fn, eeItem.ee_handle);
+ if ((nfaStat = NFA_EeModeSet (eeItem.ee_handle, NFA_EE_MD_ACTIVATE)) == NFA_STATUS_OK)
+ {
+ mEeSetModeEvent.wait (); //wait for NFA_EE_MODE_SET_EVT
+ if (eeItem.ee_status == NFC_NFCEE_STATUS_ACTIVE)
+ numActivatedEe++;
+ }
+ else
+ ALOGE ("%s: NFA_EeModeSet failed; error=0x%X", fn, nfaStat);
+ }
+ }
+ } //for
+
+ for (UINT8 xx = 0; xx < mActualNumEe; xx++)
+ {
+ if ((mEeInfo[xx].num_interface != 0) && (mEeInfo[xx].ee_interface[0] != NCI_NFCEE_INTERFACE_HCI_ACCESS) &&
+ (mEeInfo[xx].ee_status != NFC_NFCEE_STATUS_INACTIVE))
+ {
+ mActiveEeHandle = mEeInfo[xx].ee_handle;
+ break;
+ }
+ }
+
+ ALOGD ("%s: exit; ok=%u", fn, numActivatedEe > 0);
+ return numActivatedEe > 0;
+}
+
+
+/*******************************************************************************
+**
+** Function: deactivate
+**
+** Description: Turn off the secure element.
+** seID: ID of secure element.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool SecureElement::deactivate (jint seID)
+{
+ static const char fn [] = "SecureElement::deactivate";
+ tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
+ int numDeactivatedEe = 0;
+ bool retval = false;
+
+ ALOGD ("%s: enter; seID=0x%X, mActiveEeHandle=0x%X", fn, seID, mActiveEeHandle);
+
+ if (!mIsInit)
+ {
+ ALOGE ("%s: not init", fn);
+ goto TheEnd;
+ }
+
+ //if the controller is routing to sec elems or piping,
+ //then the secure element cannot be deactivated
+ if ((mCurrentRouteSelection == SecElemRoute) || mIsPiping)
+ {
+ ALOGE ("%s: still busy", fn);
+ goto TheEnd;
+ }
+
+ if (mActiveEeHandle == NFA_HANDLE_INVALID)
+ {
+ ALOGE ("%s: invalid EE handle", fn);
+ goto TheEnd;
+ }
+
+ mActiveEeHandle = NFA_HANDLE_INVALID;
+ retval = true;
+
+TheEnd:
+ ALOGD ("%s: exit; ok=%u", fn, retval);
+ return retval;
+}
+
+
+/*******************************************************************************
+**
+** Function: notifyTransactionListenersOfAid
+**
+** Description: Notify the NFC service about a transaction event from secure element.
+** aid: Buffer contains application ID.
+** aidLen: Length of application ID.
+**
+** Returns: None
+**
+*******************************************************************************/
+void SecureElement::notifyTransactionListenersOfAid (const UINT8* aidBuffer, UINT8 aidBufferLen)
+{
+ static const char fn [] = "SecureElement::notifyTransactionListenersOfAid";
+ ALOGD ("%s: enter; aid len=%u", fn, aidBufferLen);
+
+ if (aidBufferLen == 0)
+ return;
+
+ jobject tlvJavaArray = NULL;
+ JNIEnv* e = NULL;
+ UINT8* tlv = 0;
+ const UINT16 tlvMaxLen = aidBufferLen + 10;
+ UINT16 tlvActualLen = 0;
+ bool stat = false;
+
+ mNativeData->vm->AttachCurrentThread (&e, NULL);
+ if (e == NULL)
+ {
+ ALOGE ("%s: jni env is null", fn);
+ return;
+ }
+
+ tlv = new UINT8 [tlvMaxLen];
+ if (tlv == NULL)
+ {
+ ALOGE ("%s: fail allocate tlv", fn);
+ goto TheEnd;
+ }
+
+ memcpy (tlv, aidBuffer, aidBufferLen);
+ tlvActualLen = aidBufferLen;
+
+ tlvJavaArray = e->NewByteArray (tlvActualLen);
+ if (tlvJavaArray == NULL)
+ {
+ ALOGE ("%s: fail allocate array", fn);
+ goto TheEnd;
+ }
+
+ e->SetByteArrayRegion ((jbyteArray)tlvJavaArray, 0, tlvActualLen, (jbyte *)tlv);
+ if (e->ExceptionCheck())
+ {
+ e->ExceptionClear();
+ ALOGE ("%s: fail fill array", fn);
+ goto TheEnd;
+ }
+
+ e->CallVoidMethod (mNativeData->manager, android::gCachedNfcManagerNotifyTransactionListeners, tlvJavaArray);
+ if (e->ExceptionCheck())
+ {
+ e->ExceptionClear();
+ ALOGE ("%s: fail notify", fn);
+ goto TheEnd;
+ }
+
+TheEnd:
+ if (tlvJavaArray)
+ e->DeleteLocalRef (tlvJavaArray);
+ mNativeData->vm->DetachCurrentThread ();
+ delete [] tlv;
+ ALOGD ("%s: exit", fn);
+}
+
+
+/*******************************************************************************
+**
+** Function: connectEE
+**
+** Description: Connect to the execution environment.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool SecureElement::connectEE ()
+{
+ static const char fn [] = "SecureElement::connectEE";
+ tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
+ bool retVal = false;
+ UINT8 destHost = 0;
+ unsigned long num = 0;
+ char pipeConfName[40];
+ tNFA_HANDLE eeHandle = mActiveEeHandle;
+
+ ALOGD ("%s: enter, mActiveEeHandle: 0x%04x, SEID: 0x%x, pipe_gate_num=%d, use pipe=%d",
+ fn, mActiveEeHandle, gSEId, gGatePipe, gUseStaticPipe);
+
+ if (!mIsInit)
+ {
+ ALOGE ("%s: not init", fn);
+ return (false);
+ }
+
+ if (gSEId != -1)
+ {
+ eeHandle = gSEId | NFA_HANDLE_GROUP_EE;
+ ALOGD ("%s: Using SEID: 0x%x", fn, eeHandle );
+ }
+
+ if (eeHandle == NFA_HANDLE_INVALID)
+ {
+ ALOGE ("%s: invalid handle 0x%X", fn, eeHandle);
+ return (false);
+ }
+
+ tNFA_EE_INFO *pEE = findEeByHandle (eeHandle);
+
+ if (pEE == NULL)
+ {
+ ALOGE ("%s: Handle 0x%04x NOT FOUND !!", fn, eeHandle);
+ return (false);
+ }
+
+ // Disable RF discovery completely while the DH is connected
+ android::startRfDiscovery(false);
+
+ mNewSourceGate = 0;
+
+ if (gGatePipe == -1)
+ {
+ // pipe/gate num was not specifed by app, get from config file
+ mNewPipeId = 0;
+
+ // Construct the PIPE name based on the EE handle (e.g. NFA_HCI_STATIC_PIPE_ID_F3 for UICC0).
+ snprintf (pipeConfName, sizeof(pipeConfName), "NFA_HCI_STATIC_PIPE_ID_%02X", eeHandle & NFA_HANDLE_MASK);
+
+ if (GetNumValue(pipeConfName, &num, sizeof(num)) && (num != 0))
+ {
+ mNewPipeId = num;
+ ALOGD ("%s: Using static pipe id: 0x%X", __FUNCTION__, mNewPipeId);
+ }
+ else
+ {
+ ALOGD ("%s: Did not find value '%s' defined in the .conf", __FUNCTION__, pipeConfName);
+ }
+ }
+ else
+ {
+ if (gUseStaticPipe)
+ {
+ mNewPipeId = gGatePipe;
+ }
+ else
+ {
+ mNewPipeId = 0;
+ mDestinationGate= gGatePipe;
+ }
+ }
+
+ // If the .conf file had a static pipe to use, just use it.
+ if (mNewPipeId != 0)
+ {
+ UINT8 host = (mNewPipeId == STATIC_PIPE_0x70) ? 0x02 : 0x03;
+ UINT8 gate = (mNewPipeId == STATIC_PIPE_0x70) ? 0xF0 : 0xF1;
+ nfaStat = NFA_HciAddStaticPipe(mNfaHciHandle, host, gate, mNewPipeId);
+ if (nfaStat != NFA_STATUS_OK)
+ {
+ ALOGE ("%s: fail create static pipe; error=0x%X", fn, nfaStat);
+ retVal = false;
+ goto TheEnd;
+ }
+ }
+ else
+ {
+ if ( (pEE->num_tlvs >= 1) && (pEE->ee_tlv[0].tag == NFA_EE_TAG_HCI_HOST_ID) )
+ destHost = pEE->ee_tlv[0].info[0];
+ else
+ destHost = 2;
+
+ // Get a list of existing gates and pipes
+ {
+ ALOGD ("%s: get gate, pipe list", fn);
+ SyncEventGuard guard (mPipeListEvent);
+ nfaStat = NFA_HciGetGateAndPipeList (mNfaHciHandle);
+ if (nfaStat == NFA_STATUS_OK)
+ {
+ mPipeListEvent.wait();
+ if (mHciCfg.status == NFA_STATUS_OK)
+ {
+ for (UINT8 xx = 0; xx < mHciCfg.num_pipes; xx++)
+ {
+ if ( (mHciCfg.pipe[xx].dest_host == destHost)
+ && (mHciCfg.pipe[xx].dest_gate == mDestinationGate) )
+ {
+ mNewSourceGate = mHciCfg.pipe[xx].local_gate;
+ mNewPipeId = mHciCfg.pipe[xx].pipe_id;
+
+ ALOGD ("%s: found configured gate: 0x%02x pipe: 0x%02x", fn, mNewSourceGate, mNewPipeId);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (mNewSourceGate == 0)
+ {
+ ALOGD ("%s: allocate gate", fn);
+ //allocate a source gate and store in mNewSourceGate
+ SyncEventGuard guard (mAllocateGateEvent);
+ if ((nfaStat = NFA_HciAllocGate (mNfaHciHandle)) != NFA_STATUS_OK)
+ {
+ ALOGE ("%s: fail allocate source gate; error=0x%X", fn, nfaStat);
+ goto TheEnd;
+ }
+ mAllocateGateEvent.wait ();
+ if (mCommandStatus != NFA_STATUS_OK)
+ goto TheEnd;
+ }
+
+ if (mNewPipeId == 0)
+ {
+ ALOGD ("%s: create pipe", fn);
+ SyncEventGuard guard (mCreatePipeEvent);
+ nfaStat = NFA_HciCreatePipe (mNfaHciHandle, mNewSourceGate, destHost, mDestinationGate);
+ if (nfaStat != NFA_STATUS_OK)
+ {
+ ALOGE ("%s: fail create pipe; error=0x%X", fn, nfaStat);
+ goto TheEnd;
+ }
+ mCreatePipeEvent.wait ();
+ if (mCommandStatus != NFA_STATUS_OK)
+ goto TheEnd;
+ }
+
+ {
+ ALOGD ("%s: open pipe", fn);
+ SyncEventGuard guard (mPipeOpenedEvent);
+ nfaStat = NFA_HciOpenPipe (mNfaHciHandle, mNewPipeId);
+ if (nfaStat != NFA_STATUS_OK)
+ {
+ ALOGE ("%s: fail open pipe; error=0x%X", fn, nfaStat);
+ goto TheEnd;
+ }
+ mPipeOpenedEvent.wait ();
+ if (mCommandStatus != NFA_STATUS_OK)
+ goto TheEnd;
+ }
+ }
+
+ retVal = true;
+
+TheEnd:
+ mIsPiping = retVal;
+ if (!retVal)
+ {
+ // if open failed we need to de-allocate the gate
+ disconnectEE(0);
+ }
+
+ ALOGD ("%s: exit; ok=%u", fn, retVal);
+ return retVal;
+}
+
+
+/*******************************************************************************
+**
+** Function: disconnectEE
+**
+** Description: Disconnect from the execution environment.
+** seID: ID of secure element.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool SecureElement::disconnectEE (jint seID)
+{
+ static const char fn [] = "SecureElement::disconnectEE";
+ tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
+ tNFA_HANDLE eeHandle = seID;
+
+ ALOGD("%s: seID=0x%X; handle=0x%04x", fn, seID, eeHandle);
+
+ if (mUseOberthurWarmReset)
+ {
+ //send warm-reset command to Oberthur secure element which deselects the applet;
+ //this is an Oberthur-specific command;
+ ALOGD("%s: try warm-reset on pipe id 0x%X; cmd=0x%X", fn, mNewPipeId, mOberthurWarmResetCommand);
+ SyncEventGuard guard (mRegistryEvent);
+ nfaStat = NFA_HciSetRegistry (mNfaHciHandle, mNewPipeId,
+ 1, 1, &mOberthurWarmResetCommand);
+ if (nfaStat == NFA_STATUS_OK)
+ {
+ mRegistryEvent.wait ();
+ ALOGD("%s: completed warm-reset on pipe 0x%X", fn, mNewPipeId);
+ }
+ }
+
+ if (mNewSourceGate)
+ {
+ SyncEventGuard guard (mDeallocateGateEvent);
+ if ((nfaStat = NFA_HciDeallocGate (mNfaHciHandle, mNewSourceGate)) == NFA_STATUS_OK)
+ mDeallocateGateEvent.wait ();
+ else
+ ALOGE ("%s: fail dealloc gate; error=0x%X", fn, nfaStat);
+ }
+ mIsPiping = false;
+ // Re-enable RF discovery
+ // Note that it only effactuates the current configuration,
+ // so if polling/listening were configured OFF (forex because
+ // the screen was off), they will stay OFF with this call.
+ android::startRfDiscovery(true);
+ return true;
+}
+
+
+/*******************************************************************************
+**
+** Function: transceive
+**
+** Description: Send data to the secure element; read it's response.
+** xmitBuffer: Data to transmit.
+** xmitBufferSize: Length of data.
+** recvBuffer: Buffer to receive response.
+** recvBufferMaxSize: Maximum size of buffer.
+** recvBufferActualSize: Actual length of response.
+** timeoutMillisec: timeout in millisecond.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool SecureElement::transceive (UINT8* xmitBuffer, INT32 xmitBufferSize, UINT8* recvBuffer,
+ INT32 recvBufferMaxSize, INT32& recvBufferActualSize, INT32 timeoutMillisec)
+{
+ static const char fn [] = "SecureElement::transceive";
+ tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
+ bool isSuccess = false;
+ bool waitOk = false;
+ UINT8 newSelectCmd[NCI_MAX_AID_LEN + 10];
+
+ ALOGD ("%s: enter; xmitBufferSize=%ld; recvBufferMaxSize=%ld; timeout=%ld", fn, xmitBufferSize, recvBufferMaxSize, timeoutMillisec);
+
+ // Check if we need to replace an "empty" SELECT command.
+ // 1. Has there been a AID configured, and
+ // 2. Is that AID a valid length (i.e 16 bytes max), and
+ // 3. Is the APDU at least 4 bytes (for header), and
+ // 4. Is INS == 0xA4 (SELECT command), and
+ // 5. Is P1 == 0x04 (SELECT by AID), and
+ // 6. Is the APDU len 4 or 5 bytes.
+ //
+ // Note, the length of the configured AID is in the first
+ // byte, and AID starts from the 2nd byte.
+ if (mAidForEmptySelect[0] // 1
+ && (mAidForEmptySelect[0] <= NCI_MAX_AID_LEN) // 2
+ && (xmitBufferSize >= 4) // 3
+ && (xmitBuffer[1] == 0xA4) // 4
+ && (xmitBuffer[2] == 0x04) // 5
+ && (xmitBufferSize <= 5)) // 6
+ {
+ UINT8 idx = 0;
+
+ // Copy APDU command header from the input buffer.
+ memcpy(&newSelectCmd[0], &xmitBuffer[0], 4);
+ idx = 4;
+
+ // Set the Lc value to length of the new AID
+ newSelectCmd[idx++] = mAidForEmptySelect[0];
+
+ // Copy the AID
+ memcpy(&newSelectCmd[idx], &mAidForEmptySelect[1], mAidForEmptySelect[0]);
+ idx += mAidForEmptySelect[0];
+
+ // If there is an Le (5th byte of APDU), add it to the end.
+ if (xmitBufferSize == 5)
+ newSelectCmd[idx++] = xmitBuffer[4];
+
+ // Point to the new APDU
+ xmitBuffer = &newSelectCmd[0];
+ xmitBufferSize = idx;
+
+ ALOGD ("%s: Empty AID SELECT cmd detected, substituting AID from config file, new length=%d", fn, idx);
+ }
+
+ {
+ SyncEventGuard guard (mTransceiveEvent);
+ mActualResponseSize = 0;
+ memset (mResponseData, 0, sizeof(mResponseData));
+ if ((mNewPipeId == STATIC_PIPE_0x70) || (mNewPipeId == STATIC_PIPE_0x71))
+ nfaStat = NFA_HciSendEvent (mNfaHciHandle, mNewPipeId, EVT_SEND_DATA, xmitBufferSize, xmitBuffer, sizeof(mResponseData), mResponseData, 0);
+ else
+ nfaStat = NFA_HciSendEvent (mNfaHciHandle, mNewPipeId, NFA_HCI_EVT_POST_DATA, xmitBufferSize, xmitBuffer, sizeof(mResponseData), mResponseData, 0);
+
+ if (nfaStat == NFA_STATUS_OK)
+ {
+ waitOk = mTransceiveEvent.wait (timeoutMillisec);
+ if (waitOk == false) //timeout occurs
+ {
+ ALOGE ("%s: wait response timeout", fn);
+ goto TheEnd;
+ }
+ }
+ else
+ {
+ ALOGE ("%s: fail send data; error=0x%X", fn, nfaStat);
+ goto TheEnd;
+ }
+ }
+
+ if (mActualResponseSize > recvBufferMaxSize)
+ recvBufferActualSize = recvBufferMaxSize;
+ else
+ recvBufferActualSize = mActualResponseSize;
+
+ memcpy (recvBuffer, mResponseData, recvBufferActualSize);
+ isSuccess = true;
+
+TheEnd:
+ ALOGD ("%s: exit; isSuccess: %d; recvBufferActualSize: %ld", fn, isSuccess, recvBufferActualSize);
+ return (isSuccess);
+}
+
+
+/*******************************************************************************
+**
+** Function: notifyListenModeState
+**
+** Description: Notify the NFC service about whether the SE was activated
+** in listen mode.
+** isActive: Whether the secure element is activated.
+**
+** Returns: None
+**
+*******************************************************************************/
+void SecureElement::notifyListenModeState (bool isActivated) {
+ static const char fn [] = "SecureElement::notifyListenMode";
+ JNIEnv *e = NULL;
+
+ ALOGD ("%s: enter; listen mode active=%u", fn, isActivated);
+ mNativeData->vm->AttachCurrentThread (&e, NULL);
+
+ if (e == NULL)
+ {
+ ALOGE ("%s: jni env is null", fn);
+ return;
+ }
+
+ mActivatedInListenMode = isActivated;
+ if (isActivated) {
+ e->CallVoidMethod (mNativeData->manager, android::gCachedNfcManagerNotifySeListenActivated);
+ }
+ else {
+ e->CallVoidMethod (mNativeData->manager, android::gCachedNfcManagerNotifySeListenDeactivated);
+ }
+
+ if (e->ExceptionCheck())
+ {
+ e->ExceptionClear();
+ ALOGE ("%s: fail notify", fn);
+ }
+
+ mNativeData->vm->DetachCurrentThread ();
+ ALOGD ("%s: exit", fn);
+}
+
+/*******************************************************************************
+**
+** Function: notifyRfFieldEvent
+**
+** Description: Notify the NFC service about RF field events from the stack.
+** isActive: Whether any secure element is activated.
+**
+** Returns: None
+**
+*******************************************************************************/
+void SecureElement::notifyRfFieldEvent (bool isActive)
+{
+ static const char fn [] = "SecureElement::notifyRfFieldEvent";
+ JNIEnv *e = NULL;
+
+ ALOGD ("%s: enter; is active=%u", fn, isActive);
+ mNativeData->vm->AttachCurrentThread (&e, NULL);
+
+ if (e == NULL)
+ {
+ ALOGE ("%s: jni env is null", fn);
+ return;
+ }
+
+ mMutex.lock();
+ int ret = clock_gettime (CLOCK_MONOTONIC, &mLastRfFieldToggle);
+ if (ret == -1) {
+ ALOGE("%s: clock_gettime failed", fn);
+ // There is no good choice here...
+ }
+ if (isActive) {
+ mRfFieldIsOn = true;
+ e->CallVoidMethod (mNativeData->manager, android::gCachedNfcManagerNotifySeFieldActivated);
+ }
+ else {
+ mRfFieldIsOn = false;
+ e->CallVoidMethod (mNativeData->manager, android::gCachedNfcManagerNotifySeFieldDeactivated);
+ }
+ mMutex.unlock();
+
+ if (e->ExceptionCheck())
+ {
+ e->ExceptionClear();
+ ALOGE ("%s: fail notify", fn);
+ }
+ mNativeData->vm->DetachCurrentThread ();
+ ALOGD ("%s: exit", fn);
+}
+
+
+/*******************************************************************************
+**
+** Function: storeUiccInfo
+**
+** Description: Store a copy of the execution environment information from the stack.
+** info: execution environment information.
+**
+** Returns: None
+**
+*******************************************************************************/
+void SecureElement::storeUiccInfo (tNFA_EE_DISCOVER_REQ& info)
+{
+ static const char fn [] = "SecureElement::storeUiccInfo";
+ ALOGD ("%s: Status: %u Num EE: %u", fn, info.status, info.num_ee);
+
+ SyncEventGuard guard (mUiccInfoEvent);
+ memcpy (&mUiccInfo, &info, sizeof(mUiccInfo));
+ for (UINT8 xx = 0; xx < info.num_ee; xx++)
+ {
+ //for each technology (A, B, F, B'), print the bit field that shows
+ //what protocol(s) is support by that technology
+ ALOGD ("%s EE[%u] Handle: 0x%04x techA: 0x%02x techB: 0x%02x techF: 0x%02x techBprime: 0x%02x",
+ fn, xx, info.ee_disc_info[xx].ee_handle,
+ info.ee_disc_info[xx].la_protocol,
+ info.ee_disc_info[xx].lb_protocol,
+ info.ee_disc_info[xx].lf_protocol,
+ info.ee_disc_info[xx].lbp_protocol);
+ }
+ mUiccInfoEvent.notifyOne ();
+}
+
+
+/*******************************************************************************
+**
+** Function: getUiccId
+**
+** Description: Get the ID of the secure element.
+** eeHandle: Handle to the secure element.
+** uid: Array to receive the ID.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool SecureElement::getUiccId (tNFA_HANDLE eeHandle, jbyteArray& uid)
+{
+ static const char fn [] = "SecureElement::getUiccId";
+ ALOGD ("%s: ee h=0x%X", fn, eeHandle);
+ bool retval = false;
+ JNIEnv* e = NULL;
+
+ mNativeData->vm->AttachCurrentThread (&e, NULL);
+ if (e == NULL)
+ {
+ ALOGE ("%s: jni env is null", fn);
+ return false;
+ }
+
+ findUiccByHandle (eeHandle);
+ //cannot get UID from the stack; nothing to do
+
+TheEnd:
+ mNativeData->vm->DetachCurrentThread ();
+ ALOGD ("%s: exit; ret=%u", fn, retval);
+ return retval;
+}
+
+
+/*******************************************************************************
+**
+** Function: getTechnologyList
+**
+** Description: Get all the technologies supported by a secure element.
+** eeHandle: Handle of secure element.
+** techList: List to receive the technologies.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool SecureElement::getTechnologyList (tNFA_HANDLE eeHandle, jintArray& techList)
+{
+ static const char fn [] = "SecureElement::getTechnologyList";
+ ALOGD ("%s: ee h=0x%X", fn, eeHandle);
+ bool retval = false;
+ JNIEnv* e = NULL;
+ jint theList = 0;
+
+ mNativeData->vm->AttachCurrentThread (&e, NULL);
+ if (e == NULL)
+ {
+ ALOGE ("%s: jni env is null", fn);
+ return false;
+ }
+
+ tNFA_EE_DISCOVER_INFO *pUICC = findUiccByHandle (eeHandle);
+
+ if (pUICC->la_protocol != 0)
+ theList = TARGET_TYPE_ISO14443_3A;
+ else if (pUICC->lb_protocol != 0)
+ theList = TARGET_TYPE_ISO14443_3B;
+ else if (pUICC->lf_protocol != 0)
+ theList = TARGET_TYPE_FELICA;
+ else if (pUICC->lbp_protocol != 0)
+ theList = TARGET_TYPE_ISO14443_3B;
+ else
+ theList = TARGET_TYPE_UNKNOWN;
+
+TheEnd:
+ mNativeData->vm->DetachCurrentThread ();
+ ALOGD ("%s: exit; ret=%u", fn, retval);
+ return retval;
+}
+
+
+/*******************************************************************************
+**
+** Function: adjustRoutes
+**
+** Description: Adjust routes in the controller's listen-mode routing table.
+** selection: which set of routes to configure the controller.
+**
+** Returns: None
+**
+*******************************************************************************/
+void SecureElement::adjustRoutes (RouteSelection selection)
+{
+ static const char fn [] = "SecureElement::adjustRoutes";
+ ALOGD ("%s: enter; selection=%u", fn, selection);
+ tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
+ RouteDataSet::Database* db = mRouteDataSet.getDatabase (RouteDataSet::DefaultRouteDatabase);
+
+ if (selection == SecElemRoute)
+ db = mRouteDataSet.getDatabase (RouteDataSet::SecElemRouteDatabase);
+
+ mCurrentRouteSelection = selection;
+ adjustProtocolRoutes (db, selection);
+ adjustTechnologyRoutes (db, selection);
+ HostAidRouter::getInstance ().deleteAllRoutes (); //stop all AID routes to host
+
+ if (db->empty())
+ {
+ ALOGD ("%s: no route configuration", fn);
+ goto TheEnd;
+ }
+
+
+TheEnd:
+ NFA_EeUpdateNow (); //apply new routes now
+ ALOGD ("%s: exit", fn);
+}
+
+
+/*******************************************************************************
+**
+** Function: applyRoutes
+**
+** Description: Read route data from file and apply them again.
+**
+** Returns: None
+**
+*******************************************************************************/
+void SecureElement::applyRoutes ()
+{
+ static const char fn [] = "SecureElement::applyRoutes";
+ ALOGD ("%s: enter", fn);
+ if (mCurrentRouteSelection != NoRoute)
+ {
+ mRouteDataSet.import (); //read XML file
+ adjustRoutes (mCurrentRouteSelection);
+ }
+ ALOGD ("%s: exit", fn);
+}
+
+
+/*******************************************************************************
+**
+** Function: adjustProtocolRoutes
+**
+** Description: Adjust default routing based on protocol in NFC listen mode.
+** isRouteToEe: Whether routing to EE (true) or host (false).
+**
+** Returns: None
+**
+*******************************************************************************/
+void SecureElement::adjustProtocolRoutes (RouteDataSet::Database* db, RouteSelection routeSelection)
+{
+ static const char fn [] = "SecureElement::adjustProtocolRoutes";
+ ALOGD ("%s: enter", fn);
+ tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
+ const tNFA_PROTOCOL_MASK protoMask = NFA_PROTOCOL_MASK_ISO_DEP;
+
+ ///////////////////////
+ // delete route to host
+ ///////////////////////
+ {
+ ALOGD ("%s: delete route to host", fn);
+ SyncEventGuard guard (mRoutingEvent);
+ if ((nfaStat = NFA_EeSetDefaultProtoRouting (NFA_EE_HANDLE_DH, 0, 0, 0)) == NFA_STATUS_OK)
+ mRoutingEvent.wait ();
+ else
+ ALOGE ("%s: fail delete route to host; error=0x%X", fn, nfaStat);
+ }
+
+ ///////////////////////
+ // delete route to every sec elem
+ ///////////////////////
+ for (int i=0; i < mActualNumEe; i++)
+ {
+ if ((mEeInfo[i].num_interface != 0) &&
+ (mEeInfo[i].ee_interface[0] != NFC_NFCEE_INTERFACE_HCI_ACCESS) &&
+ (mEeInfo[i].ee_status == NFA_EE_STATUS_ACTIVE))
+ {
+ ALOGD ("%s: delete route to EE h=0x%X", fn, mEeInfo[i].ee_handle);
+ SyncEventGuard guard (mRoutingEvent);
+ if ((nfaStat = NFA_EeSetDefaultProtoRouting (mEeInfo[i].ee_handle, 0, 0, 0)) == NFA_STATUS_OK)
+ mRoutingEvent.wait ();
+ else
+ ALOGE ("%s: fail delete route to EE; error=0x%X", fn, nfaStat);
+ }
+ }
+
+ //////////////////////
+ // configure route for every discovered sec elem
+ //////////////////////
+ for (int i=0; i < mActualNumEe; i++)
+ {
+ //if sec elem is active
+ if ((mEeInfo[i].num_interface != 0) &&
+ (mEeInfo[i].ee_interface[0] != NFC_NFCEE_INTERFACE_HCI_ACCESS) &&
+ (mEeInfo[i].ee_status == NFA_EE_STATUS_ACTIVE))
+ {
+ tNFA_PROTOCOL_MASK protocolsSwitchOn = 0; //all protocols that are active at full power
+ tNFA_PROTOCOL_MASK protocolsSwitchOff = 0; //all protocols that are active when phone is turned off
+ tNFA_PROTOCOL_MASK protocolsBatteryOff = 0; //all protocols that are active when there is no power
+
+ //for every route in XML, look for protocol route;
+ //collect every protocol according to it's desired power mode
+ for (RouteDataSet::Database::iterator iter = db->begin(); iter != db->end(); iter++)
+ {
+ RouteData* routeData = *iter;
+ RouteDataForProtocol* route = NULL;
+ if (routeData->mRouteType != RouteData::ProtocolRoute)
+ continue; //skip other kinds of routing data
+ route = (RouteDataForProtocol*) (*iter);
+ if (route->mNfaEeHandle == mEeInfo[i].ee_handle)
+ {
+ if (route->mSwitchOn)
+ protocolsSwitchOn |= route->mProtocol;
+ if (route->mSwitchOff)
+ protocolsSwitchOff |= route->mProtocol;
+ if (route->mBatteryOff)
+ protocolsBatteryOff |= route->mProtocol;
+ }
+ }
+
+ if (protocolsSwitchOn | protocolsSwitchOff | protocolsBatteryOff)
+ {
+ ALOGD ("%s: route to EE h=0x%X", fn, mEeInfo[i].ee_handle);
+ SyncEventGuard guard (mRoutingEvent);
+ nfaStat = NFA_EeSetDefaultProtoRouting (mEeInfo[i].ee_handle,
+ protocolsSwitchOn, protocolsSwitchOff, protocolsBatteryOff);
+ if (nfaStat == NFA_STATUS_OK)
+ mRoutingEvent.wait ();
+ else
+ ALOGE ("%s: fail route to EE; error=0x%X", fn, nfaStat);
+ }
+ } //if sec elem is active
+ } //for every discovered sec elem
+
+ //////////////////////
+ // configure route to host
+ //////////////////////
+ {
+ tNFA_PROTOCOL_MASK protocolsSwitchOn = 0; //all protocols that are active at full power
+ tNFA_PROTOCOL_MASK protocolsSwitchOff = 0; //all protocols that are active when phone is turned off
+ tNFA_PROTOCOL_MASK protocolsBatteryOff = 0; //all protocols that are active when there is no power
+
+ //for every route in XML, look for protocol route;
+ //collect every protocol according to it's desired power mode
+ for (RouteDataSet::Database::iterator iter = db->begin(); iter != db->end(); iter++)
+ {
+ RouteData* routeData = *iter;
+ RouteDataForProtocol* route = NULL;
+ if (routeData->mRouteType != RouteData::ProtocolRoute)
+ continue; //skip other kinds of routing data
+ route = (RouteDataForProtocol*) (*iter);
+ if (route->mNfaEeHandle == NFA_EE_HANDLE_DH)
+ {
+ if (route->mSwitchOn)
+ protocolsSwitchOn |= route->mProtocol;
+ if (route->mSwitchOff)
+ protocolsSwitchOff |= route->mProtocol;
+ if (route->mBatteryOff)
+ protocolsBatteryOff |= route->mProtocol;
+ }
+ }
+
+ if (protocolsSwitchOn | protocolsSwitchOff | protocolsBatteryOff)
+ {
+ ALOGD ("%s: route to EE h=0x%X", fn, NFA_EE_HANDLE_DH);
+ SyncEventGuard guard (mRoutingEvent);
+ nfaStat = NFA_EeSetDefaultProtoRouting (NFA_EE_HANDLE_DH,
+ protocolsSwitchOn, protocolsSwitchOff, protocolsBatteryOff);
+ if (nfaStat == NFA_STATUS_OK)
+ mRoutingEvent.wait ();
+ else
+ ALOGE ("%s: fail route to EE; error=0x%X", fn, nfaStat);
+ }
+ }
+
+ //////////////////////
+ // if route database is empty, setup a default route
+ //////////////////////
+ if (db->empty())
+ {
+ tNFA_HANDLE eeHandle = NFA_EE_HANDLE_DH;
+ if (routeSelection == SecElemRoute)
+ eeHandle = getDefaultEeHandle ();
+ ALOGD ("%s: route to default EE h=0x%X", fn, eeHandle);
+ SyncEventGuard guard (mRoutingEvent);
+ nfaStat = NFA_EeSetDefaultProtoRouting (eeHandle, protoMask, 0, 0);
+ if (nfaStat == NFA_STATUS_OK)
+ mRoutingEvent.wait ();
+ else
+ ALOGE ("%s: fail route to EE; error=0x%X", fn, nfaStat);
+ }
+ ALOGD ("%s: exit", fn);
+}
+
+
+/*******************************************************************************
+**
+** Function: adjustTechnologyRoutes
+**
+** Description: Adjust default routing based on technology in NFC listen mode.
+** isRouteToEe: Whether routing to EE (true) or host (false).
+**
+** Returns: None
+**
+*******************************************************************************/
+void SecureElement::adjustTechnologyRoutes (RouteDataSet::Database* db, RouteSelection routeSelection)
+{
+ static const char fn [] = "SecureElement::adjustTechnologyRoutes";
+ ALOGD ("%s: enter", fn);
+ tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
+ const tNFA_TECHNOLOGY_MASK techMask = NFA_TECHNOLOGY_MASK_A | NFA_TECHNOLOGY_MASK_B;
+
+ ///////////////////////
+ // delete route to host
+ ///////////////////////
+ {
+ ALOGD ("%s: delete route to host", fn);
+ SyncEventGuard guard (mRoutingEvent);
+ if ((nfaStat = NFA_EeSetDefaultTechRouting (NFA_EE_HANDLE_DH, 0, 0, 0)) == NFA_STATUS_OK)
+ mRoutingEvent.wait ();
+ else
+ ALOGE ("%s: fail delete route to host; error=0x%X", fn, nfaStat);
+ }
+
+ ///////////////////////
+ // delete route to every sec elem
+ ///////////////////////
+ for (int i=0; i < mActualNumEe; i++)
+ {
+ if ((mEeInfo[i].num_interface != 0) &&
+ (mEeInfo[i].ee_interface[0] != NFC_NFCEE_INTERFACE_HCI_ACCESS) &&
+ (mEeInfo[i].ee_status == NFA_EE_STATUS_ACTIVE))
+ {
+ ALOGD ("%s: delete route to EE h=0x%X", fn, mEeInfo[i].ee_handle);
+ SyncEventGuard guard (mRoutingEvent);
+ if ((nfaStat = NFA_EeSetDefaultTechRouting (mEeInfo[i].ee_handle, 0, 0, 0)) == NFA_STATUS_OK)
+ mRoutingEvent.wait ();
+ else
+ ALOGE ("%s: fail delete route to EE; error=0x%X", fn, nfaStat);
+ }
+ }
+
+ //////////////////////
+ // configure route for every discovered sec elem
+ //////////////////////
+ for (int i=0; i < mActualNumEe; i++)
+ {
+ //if sec elem is active
+ if ((mEeInfo[i].num_interface != 0) &&
+ (mEeInfo[i].ee_interface[0] != NFC_NFCEE_INTERFACE_HCI_ACCESS) &&
+ (mEeInfo[i].ee_status == NFA_EE_STATUS_ACTIVE))
+ {
+ tNFA_TECHNOLOGY_MASK techsSwitchOn = 0; //all techs that are active at full power
+ tNFA_TECHNOLOGY_MASK techsSwitchOff = 0; //all techs that are active when phone is turned off
+ tNFA_TECHNOLOGY_MASK techsBatteryOff = 0; //all techs that are active when there is no power
+
+ //for every route in XML, look for tech route;
+ //collect every tech according to it's desired power mode
+ for (RouteDataSet::Database::iterator iter = db->begin(); iter != db->end(); iter++)
+ {
+ RouteData* routeData = *iter;
+ RouteDataForTechnology* route = NULL;
+ if (routeData->mRouteType != RouteData::TechnologyRoute)
+ continue; //skip other kinds of routing data
+ route = (RouteDataForTechnology*) (*iter);
+ if (route->mNfaEeHandle == mEeInfo[i].ee_handle)
+ {
+ if (route->mSwitchOn)
+ techsSwitchOn |= route->mTechnology;
+ if (route->mSwitchOff)
+ techsSwitchOff |= route->mTechnology;
+ if (route->mBatteryOff)
+ techsBatteryOff |= route->mTechnology;
+ }
+ }
+
+ if (techsSwitchOn | techsSwitchOff | techsBatteryOff)
+ {
+ ALOGD ("%s: route to EE h=0x%X", fn, mEeInfo[i].ee_handle);
+ SyncEventGuard guard (mRoutingEvent);
+ nfaStat = NFA_EeSetDefaultTechRouting (mEeInfo[i].ee_handle,
+ techsSwitchOn, techsSwitchOff, techsBatteryOff);
+ if (nfaStat == NFA_STATUS_OK)
+ mRoutingEvent.wait ();
+ else
+ ALOGE ("%s: fail route to EE; error=0x%X", fn, nfaStat);
+ }
+ } //if sec elem is active
+ } //for every discovered sec elem
+
+ //////////////////////
+ // configure route to host
+ //////////////////////
+ {
+ tNFA_TECHNOLOGY_MASK techsSwitchOn = 0; //all techs that are active at full power
+ tNFA_TECHNOLOGY_MASK techsSwitchOff = 0; //all techs that are active when phone is turned off
+ tNFA_TECHNOLOGY_MASK techsBatteryOff = 0; //all techs that are active when there is no power
+
+ //for every route in XML, look for protocol route;
+ //collect every protocol according to it's desired power mode
+ for (RouteDataSet::Database::iterator iter = db->begin(); iter != db->end(); iter++)
+ {
+ RouteData* routeData = *iter;
+ RouteDataForTechnology * route = NULL;
+ if (routeData->mRouteType != RouteData::TechnologyRoute)
+ continue; //skip other kinds of routing data
+ route = (RouteDataForTechnology*) (*iter);
+ if (route->mNfaEeHandle == NFA_EE_HANDLE_DH)
+ {
+ if (route->mSwitchOn)
+ techsSwitchOn |= route->mTechnology;
+ if (route->mSwitchOff)
+ techsSwitchOff |= route->mTechnology;
+ if (route->mBatteryOff)
+ techsBatteryOff |= route->mTechnology;
+ }
+ }
+
+ if (techsSwitchOn | techsSwitchOff | techsBatteryOff)
+ {
+ ALOGD ("%s: route to EE h=0x%X", fn, NFA_EE_HANDLE_DH);
+ SyncEventGuard guard (mRoutingEvent);
+ nfaStat = NFA_EeSetDefaultTechRouting (NFA_EE_HANDLE_DH,
+ techsSwitchOn, techsSwitchOff, techsBatteryOff);
+ if (nfaStat == NFA_STATUS_OK)
+ mRoutingEvent.wait ();
+ else
+ ALOGE ("%s: fail route to EE; error=0x%X", fn, nfaStat);
+ }
+ }
+
+ //////////////////////
+ // if route database is empty, setup a default route
+ //////////////////////
+ if (db->empty())
+ {
+ tNFA_HANDLE eeHandle = NFA_EE_HANDLE_DH;
+ if (routeSelection == SecElemRoute)
+ eeHandle = getDefaultEeHandle ();
+ ALOGD ("%s: route to default EE h=0x%X", fn, eeHandle);
+ SyncEventGuard guard (mRoutingEvent);
+ nfaStat = NFA_EeSetDefaultTechRouting (eeHandle, techMask, 0, 0);
+ if (nfaStat == NFA_STATUS_OK)
+ mRoutingEvent.wait ();
+ else
+ ALOGE ("%s: fail route to EE; error=0x%X", fn, nfaStat);
+ }
+ ALOGD ("%s: exit", fn);
+}
+
+
+/*******************************************************************************
+**
+** Function: nfaEeCallback
+**
+** Description: Receive execution environment-related events from stack.
+** event: Event code.
+** eventData: Event data.
+**
+** Returns: None
+**
+*******************************************************************************/
+void SecureElement::nfaEeCallback (tNFA_EE_EVT event, tNFA_EE_CBACK_DATA* eventData)
+{
+ static const char fn [] = "SecureElement::nfaEeCallback";
+
+ switch (event)
+ {
+ case NFA_EE_REGISTER_EVT:
+ {
+ SyncEventGuard guard (sSecElem.mEeRegisterEvent);
+ ALOGD ("%s: NFA_EE_REGISTER_EVT; status=%u", fn, eventData->ee_register);
+ sSecElem.mEeRegisterEvent.notifyOne();
+ }
+ break;
+
+ case NFA_EE_MODE_SET_EVT:
+ {
+ ALOGD ("%s: NFA_EE_MODE_SET_EVT; status: 0x%04X handle: 0x%04X mActiveEeHandle: 0x%04X", fn,
+ eventData->mode_set.status, eventData->mode_set.ee_handle, sSecElem.mActiveEeHandle);
+
+ if (eventData->mode_set.status == NFA_STATUS_OK)
+ {
+ tNFA_EE_INFO *pEE = sSecElem.findEeByHandle (eventData->mode_set.ee_handle);
+ if (pEE)
+ {
+ pEE->ee_status ^= 1;
+ ALOGD ("%s: NFA_EE_MODE_SET_EVT; pEE->ee_status: %s (0x%04x)", fn, SecureElement::eeStatusToString(pEE->ee_status), pEE->ee_status);
+ }
+ else
+ ALOGE ("%s: NFA_EE_MODE_SET_EVT; EE: 0x%04x not found. mActiveEeHandle: 0x%04x", fn, eventData->mode_set.ee_handle, sSecElem.mActiveEeHandle);
+ }
+ SyncEventGuard guard (sSecElem.mEeSetModeEvent);
+ sSecElem.mEeSetModeEvent.notifyOne();
+ }
+ break;
+
+ case NFA_EE_SET_TECH_CFG_EVT:
+ {
+ ALOGD ("%s: NFA_EE_SET_TECH_CFG_EVT; status=0x%X", fn, eventData->status);
+ SyncEventGuard guard (sSecElem.mRoutingEvent);
+ sSecElem.mRoutingEvent.notifyOne ();
+ }
+ break;
+
+ case NFA_EE_SET_PROTO_CFG_EVT:
+ {
+ ALOGD ("%s: NFA_EE_SET_PROTO_CFG_EVT; status=0x%X", fn, eventData->status);
+ SyncEventGuard guard (sSecElem.mRoutingEvent);
+ sSecElem.mRoutingEvent.notifyOne ();
+ }
+ break;
+
+ case NFA_EE_ACTION_EVT:
+ {
+ tNFA_EE_ACTION& action = eventData->action;
+ if (action.trigger == NFC_EE_TRIG_SELECT)
+ ALOGD ("%s: NFA_EE_ACTION_EVT; h=0x%X; trigger=select (0x%X)", fn, action.ee_handle, action.trigger);
+ else if (action.trigger == NFC_EE_TRIG_APP_INIT)
+ {
+ tNFC_APP_INIT& app_init = action.param.app_init;
+ ALOGD ("%s: NFA_EE_ACTION_EVT; h=0x%X; trigger=app-init (0x%X); aid len=%u; data len=%u", fn,
+ action.ee_handle, action.trigger, app_init.len_aid, app_init.len_data);
+ //if app-init operation is successful;
+ //app_init.data[] contains two bytes, which are the status codes of the event;
+ //app_init.data[] does not contain an APDU response;
+ //see EMV Contactless Specification for Payment Systems; Book B; Entry Point Specification;
+ //version 2.1; March 2011; section 3.3.3.5;
+ if ( (app_init.len_data > 1) &&
+ (app_init.data[0] == 0x90) &&
+ (app_init.data[1] == 0x00) )
+ {
+ sSecElem.notifyTransactionListenersOfAid (app_init.aid, app_init.len_aid);
+ }
+ }
+ else if (action.trigger == NFC_EE_TRIG_RF_PROTOCOL)
+ ALOGD ("%s: NFA_EE_ACTION_EVT; h=0x%X; trigger=rf protocol (0x%X)", fn, action.ee_handle, action.trigger);
+ else if (action.trigger == NFC_EE_TRIG_RF_TECHNOLOGY)
+ ALOGD ("%s: NFA_EE_ACTION_EVT; h=0x%X; trigger=rf tech (0x%X)", fn, action.ee_handle, action.trigger);
+ else
+ ALOGE ("%s: NFA_EE_ACTION_EVT; h=0x%X; unknown trigger (0x%X)", fn, action.ee_handle, action.trigger);
+ }
+ break;
+
+ case NFA_EE_DISCOVER_REQ_EVT:
+ ALOGD ("%s: NFA_EE_DISCOVER_REQ_EVT; status=0x%X; num ee=%u", __FUNCTION__,
+ eventData->discover_req.status, eventData->discover_req.num_ee);
+ sSecElem.storeUiccInfo (eventData->discover_req);
+ break;
+
+ case NFA_EE_NO_CB_ERR_EVT:
+ ALOGD ("%s: NFA_EE_NO_CB_ERR_EVT status=%u", fn, eventData->status);
+ break;
+
+ case NFA_EE_ADD_AID_EVT:
+ {
+ ALOGD ("%s: NFA_EE_ADD_AID_EVT status=%u", fn, eventData->status);
+ SyncEventGuard guard (sSecElem.mAidAddRemoveEvent);
+ sSecElem.mAidAddRemoveEvent.notifyOne ();
+ }
+ break;
+
+ case NFA_EE_REMOVE_AID_EVT:
+ {
+ ALOGD ("%s: NFA_EE_REMOVE_AID_EVT status=%u", fn, eventData->status);
+ SyncEventGuard guard (sSecElem.mAidAddRemoveEvent);
+ sSecElem.mAidAddRemoveEvent.notifyOne ();
+ }
+ break;
+
+ case NFA_EE_NEW_EE_EVT:
+ {
+ ALOGD ("%s: NFA_EE_NEW_EE_EVT h=0x%X; status=%u", fn,
+ eventData->new_ee.ee_handle, eventData->new_ee.ee_status);
+ // Indicate there are new EE
+ sSecElem.mbNewEE = true;
+ }
+ break;
+
+ default:
+ ALOGE ("%s: unknown event=%u ????", fn, event);
+ break;
+ }
+}
+
+/*******************************************************************************
+**
+** Function getSeVerInfo
+**
+** Description Gets version information and id for a secure element. The
+** seIndex parmeter is the zero based index of the secure
+** element to get verion info for. The version infommation
+** is returned as a string int the verInfo parameter.
+**
+** Returns ture on success, false on failure
+**
+*******************************************************************************/
+bool SecureElement::getSeVerInfo(int seIndex, char * verInfo, int verInfoSz, UINT8 * seid)
+{
+ ALOGD("%s: enter, seIndex=%d", __FUNCTION__, seIndex);
+
+ if (seIndex > (mActualNumEe-1))
+ {
+ ALOGE("%s: invalid se index: %d, only %d SEs in system", __FUNCTION__, seIndex, mActualNumEe);
+ return false;
+ }
+
+ *seid = mEeInfo[seIndex].ee_handle;
+
+ if ((mEeInfo[seIndex].num_interface == 0) || (mEeInfo[seIndex].ee_interface[0] == NCI_NFCEE_INTERFACE_HCI_ACCESS) )
+ {
+ return false;
+ }
+
+ strncpy(verInfo, "Version info not available", verInfoSz-1);
+ verInfo[verInfoSz-1] = '\0';
+
+ UINT8 pipe = (mEeInfo[seIndex].ee_handle == EE_HANDLE_0xF3) ? 0x70 : 0x71;
+ UINT8 host = (pipe == STATIC_PIPE_0x70) ? 0x02 : 0x03;
+ UINT8 gate = (pipe == STATIC_PIPE_0x70) ? 0xF0 : 0xF1;
+
+ tNFA_STATUS nfaStat = NFA_HciAddStaticPipe(mNfaHciHandle, host, gate, pipe);
+ if (nfaStat != NFA_STATUS_OK)
+ {
+ ALOGE ("%s: NFA_HciAddStaticPipe() failed, pipe = 0x%x, error=0x%X", __FUNCTION__, pipe, nfaStat);
+ return true;
+ }
+
+ SyncEventGuard guard (mVerInfoEvent);
+ if (NFA_STATUS_OK == (nfaStat = NFA_HciGetRegistry (mNfaHciHandle, pipe, 0x02)))
+ {
+ if (false == mVerInfoEvent.wait(200))
+ {
+ ALOGE ("%s: wait response timeout", __FUNCTION__);
+ }
+ else
+ {
+ snprintf(verInfo, verInfoSz-1, "Oberthur OS S/N: 0x%02x%02x%02x", mVerInfo[0], mVerInfo[1], mVerInfo[2]);
+ verInfo[verInfoSz-1] = '\0';
+ }
+ }
+ else
+ {
+ ALOGE ("%s: NFA_HciGetRegistry () failed: 0x%X", __FUNCTION__, nfaStat);
+ }
+ return true;
+}
+
+/*******************************************************************************
+**
+** Function getActualNumEe
+**
+** Description Returns number of secure elements we know about.
+**
+** Returns Number of secure elements we know about.
+**
+*******************************************************************************/
+UINT8 SecureElement::getActualNumEe()
+{
+ return mActualNumEe;
+}
+
+/*******************************************************************************
+**
+** Function: nfaHciCallback
+**
+** Description: Receive Host Controller Interface-related events from stack.
+** event: Event code.
+** eventData: Event data.
+**
+** Returns: None
+**
+*******************************************************************************/
+void SecureElement::nfaHciCallback (tNFA_HCI_EVT event, tNFA_HCI_EVT_DATA* eventData)
+{
+ static const char fn [] = "SecureElement::nfaHciCallback";
+ ALOGD ("%s: event=0x%X", fn, event);
+
+ switch (event)
+ {
+ case NFA_HCI_REGISTER_EVT:
+ {
+ ALOGD ("%s: NFA_HCI_REGISTER_EVT; status=0x%X; handle=0x%X", fn,
+ eventData->hci_register.status, eventData->hci_register.hci_handle);
+ SyncEventGuard guard (sSecElem.mHciRegisterEvent);
+ sSecElem.mNfaHciHandle = eventData->hci_register.hci_handle;
+ sSecElem.mHciRegisterEvent.notifyOne();
+ }
+ break;
+
+ case NFA_HCI_ALLOCATE_GATE_EVT:
+ {
+ ALOGD ("%s: NFA_HCI_ALLOCATE_GATE_EVT; status=0x%X; gate=0x%X", fn, eventData->status, eventData->allocated.gate);
+ SyncEventGuard guard (sSecElem.mAllocateGateEvent);
+ sSecElem.mCommandStatus = eventData->status;
+ sSecElem.mNewSourceGate = (eventData->allocated.status == NFA_STATUS_OK) ? eventData->allocated.gate : 0;
+ sSecElem.mAllocateGateEvent.notifyOne();
+ }
+ break;
+
+ case NFA_HCI_DEALLOCATE_GATE_EVT:
+ {
+ tNFA_HCI_DEALLOCATE_GATE& deallocated = eventData->deallocated;
+ ALOGD ("%s: NFA_HCI_DEALLOCATE_GATE_EVT; status=0x%X; gate=0x%X", fn, deallocated.status, deallocated.gate);
+ SyncEventGuard guard (sSecElem.mDeallocateGateEvent);
+ sSecElem.mDeallocateGateEvent.notifyOne();
+ }
+ break;
+
+ case NFA_HCI_GET_GATE_PIPE_LIST_EVT:
+ {
+ ALOGD ("%s: NFA_HCI_GET_GATE_PIPE_LIST_EVT; status=0x%X; num_pipes: %u num_gates: %u", fn,
+ eventData->gates_pipes.status, eventData->gates_pipes.num_pipes, eventData->gates_pipes.num_gates);
+ SyncEventGuard guard (sSecElem.mPipeListEvent);
+ sSecElem.mCommandStatus = eventData->gates_pipes.status;
+ sSecElem.mHciCfg = eventData->gates_pipes;
+ sSecElem.mPipeListEvent.notifyOne();
+ }
+ break;
+
+ case NFA_HCI_CREATE_PIPE_EVT:
+ {
+ ALOGD ("%s: NFA_HCI_CREATE_PIPE_EVT; status=0x%X; pipe=0x%X; src gate=0x%X; dest host=0x%X; dest gate=0x%X", fn,
+ eventData->created.status, eventData->created.pipe, eventData->created.source_gate, eventData->created.dest_host, eventData->created.dest_gate);
+ SyncEventGuard guard (sSecElem.mCreatePipeEvent);
+ sSecElem.mCommandStatus = eventData->created.status;
+ sSecElem.mNewPipeId = eventData->created.pipe;
+ sSecElem.mCreatePipeEvent.notifyOne();
+ }
+ break;
+
+ case NFA_HCI_OPEN_PIPE_EVT:
+ {
+ ALOGD ("%s: NFA_HCI_OPEN_PIPE_EVT; status=0x%X; pipe=0x%X", fn, eventData->opened.status, eventData->opened.pipe);
+ SyncEventGuard guard (sSecElem.mPipeOpenedEvent);
+ sSecElem.mCommandStatus = eventData->opened.status;
+ sSecElem.mPipeOpenedEvent.notifyOne();
+ }
+ break;
+
+ case NFA_HCI_EVENT_SENT_EVT:
+ ALOGD ("%s: NFA_HCI_EVENT_SENT_EVT; status=0x%X", fn, eventData->evt_sent.status);
+ break;
+
+ case NFA_HCI_RSP_RCVD_EVT: //response received from secure element
+ {
+ tNFA_HCI_RSP_RCVD& rsp_rcvd = eventData->rsp_rcvd;
+ ALOGD ("%s: NFA_HCI_RSP_RCVD_EVT; status: 0x%X; code: 0x%X; pipe: 0x%X; len: %u", fn,
+ rsp_rcvd.status, rsp_rcvd.rsp_code, rsp_rcvd.pipe, rsp_rcvd.rsp_len);
+ }
+ break;
+
+ case NFA_HCI_GET_REG_RSP_EVT :
+ ALOGD ("%s: NFA_HCI_GET_REG_RSP_EVT; status: 0x%X; pipe: 0x%X, len: %d", fn,
+ eventData->registry.status, eventData->registry.pipe, eventData->registry.data_len);
+ if (eventData->registry.data_len >= 19 && ((eventData->registry.pipe == STATIC_PIPE_0x70) || (eventData->registry.pipe == STATIC_PIPE_0x71)))
+ {
+ SyncEventGuard guard (sSecElem.mVerInfoEvent);
+ // Oberthur OS version is in bytes 16,17, and 18
+ sSecElem.mVerInfo[0] = eventData->registry.reg_data[16];
+ sSecElem.mVerInfo[1] = eventData->registry.reg_data[17];
+ sSecElem.mVerInfo[2] = eventData->registry.reg_data[18];
+ sSecElem.mVerInfoEvent.notifyOne ();
+ }
+ break;
+
+ case NFA_HCI_EVENT_RCVD_EVT:
+ ALOGD ("%s: NFA_HCI_EVENT_RCVD_EVT; code: 0x%X; pipe: 0x%X; data len: %u", fn,
+ eventData->rcvd_evt.evt_code, eventData->rcvd_evt.pipe, eventData->rcvd_evt.evt_len);
+ if ((eventData->rcvd_evt.pipe == STATIC_PIPE_0x70) || (eventData->rcvd_evt.pipe == STATIC_PIPE_0x71))
+ {
+ ALOGD ("%s: NFA_HCI_EVENT_RCVD_EVT; data from static pipe", fn);
+ SyncEventGuard guard (sSecElem.mTransceiveEvent);
+ sSecElem.mActualResponseSize = (eventData->rcvd_evt.evt_len > MAX_RESPONSE_SIZE) ? MAX_RESPONSE_SIZE : eventData->rcvd_evt.evt_len;
+ sSecElem.mTransceiveEvent.notifyOne ();
+ }
+ else if (eventData->rcvd_evt.evt_code == NFA_HCI_EVT_POST_DATA)
+ {
+ ALOGD ("%s: NFA_HCI_EVENT_RCVD_EVT; NFA_HCI_EVT_POST_DATA", fn);
+ SyncEventGuard guard (sSecElem.mTransceiveEvent);
+ sSecElem.mActualResponseSize = (eventData->rcvd_evt.evt_len > MAX_RESPONSE_SIZE) ? MAX_RESPONSE_SIZE : eventData->rcvd_evt.evt_len;
+ sSecElem.mTransceiveEvent.notifyOne ();
+ }
+ else if (eventData->rcvd_evt.evt_code == NFA_HCI_EVT_TRANSACTION)
+ {
+ ALOGD ("%s: NFA_HCI_EVENT_RCVD_EVT; NFA_HCI_EVT_TRANSACTION", fn);
+ // If we got an AID, notify any listeners
+ if ((eventData->rcvd_evt.evt_len > 3) && (eventData->rcvd_evt.p_evt_buf[0] == 0x81) )
+ sSecElem.notifyTransactionListenersOfAid (&eventData->rcvd_evt.p_evt_buf[2], eventData->rcvd_evt.p_evt_buf[1]);
+ }
+ break;
+
+ case NFA_HCI_SET_REG_RSP_EVT: //received response to write registry command
+ {
+ tNFA_HCI_REGISTRY& registry = eventData->registry;
+ ALOGD ("%s: NFA_HCI_SET_REG_RSP_EVT; status=0x%X; pipe=0x%X", fn, registry.status, registry.pipe);
+ SyncEventGuard guard (sSecElem.mRegistryEvent);
+ sSecElem.mRegistryEvent.notifyOne ();
+ break;
+ }
+
+ default:
+ ALOGE ("%s: unknown event code=0x%X ????", fn, event);
+ break;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: findEeByHandle
+**
+** Description: Find information about an execution environment.
+** eeHandle: Handle to execution environment.
+**
+** Returns: Information about an execution environment.
+**
+*******************************************************************************/
+tNFA_EE_INFO *SecureElement::findEeByHandle (tNFA_HANDLE eeHandle)
+{
+ for (UINT8 xx = 0; xx < mActualNumEe; xx++)
+ {
+ if (mEeInfo[xx].ee_handle == eeHandle)
+ return (&mEeInfo[xx]);
+ }
+ return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function: getDefaultEeHandle
+**
+** Description: Get the handle to the execution environment.
+**
+** Returns: Handle to the execution environment.
+**
+*******************************************************************************/
+tNFA_HANDLE SecureElement::getDefaultEeHandle ()
+{
+ // Find the first EE that is not the HCI Access i/f.
+ for (UINT8 xx = 0; xx < mActualNumEe; xx++)
+ {
+ if ((mEeInfo[xx].num_interface != 0) && (mEeInfo[xx].ee_interface[0] != NCI_NFCEE_INTERFACE_HCI_ACCESS) )
+ return (mEeInfo[xx].ee_handle);
+ }
+ return NFA_HANDLE_INVALID;
+}
+
+
+ /*******************************************************************************
+ **
+ ** Function: findUiccByHandle
+ **
+ ** Description: Find information about an execution environment.
+ ** eeHandle: Handle of the execution environment.
+ **
+ ** Returns: Information about the execution environment.
+ **
+ *******************************************************************************/
+tNFA_EE_DISCOVER_INFO *SecureElement::findUiccByHandle (tNFA_HANDLE eeHandle)
+{
+ for (UINT8 index = 0; index < mUiccInfo.num_ee; index++)
+ {
+ if (mUiccInfo.ee_disc_info[index].ee_handle == eeHandle)
+ {
+ return (&mUiccInfo.ee_disc_info[index]);
+ }
+ }
+ ALOGE ("SecureElement::findUiccByHandle: ee h=0x%4x not found", eeHandle);
+ return NULL;
+}
+
+
+/*******************************************************************************
+**
+** Function: eeStatusToString
+**
+** Description: Convert status code to status text.
+** status: Status code
+**
+** Returns: None
+**
+*******************************************************************************/
+const char* SecureElement::eeStatusToString (UINT8 status)
+{
+ switch (status)
+ {
+ case NFC_NFCEE_STATUS_ACTIVE:
+ return("Connected/Active");
+ case NFC_NFCEE_STATUS_INACTIVE:
+ return("Connected/Inactive");
+ case NFC_NFCEE_STATUS_REMOVED:
+ return("Removed");
+ }
+ return("?? Unknown ??");
+}
+
+
+/*******************************************************************************
+**
+** Function: connectionEventHandler
+**
+** Description: Receive card-emulation related events from stack.
+** event: Event code.
+** eventData: Event data.
+**
+** Returns: None
+**
+*******************************************************************************/
+void SecureElement::connectionEventHandler (UINT8 event, tNFA_CONN_EVT_DATA* eventData)
+{
+ switch (event)
+ {
+ case NFA_CE_UICC_LISTEN_CONFIGURED_EVT:
+ {
+ SyncEventGuard guard (mUiccListenEvent);
+ mUiccListenEvent.notifyOne ();
+ }
+ break;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: routeToSecureElement
+**
+** Description: Adjust controller's listen-mode routing table so transactions
+** are routed to the secure elements.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool SecureElement::routeToSecureElement ()
+{
+ static const char fn [] = "SecureElement::routeToSecureElement";
+ ALOGD ("%s: enter", fn);
+ tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
+ tNFA_TECHNOLOGY_MASK tech_mask = NFA_TECHNOLOGY_MASK_A | NFA_TECHNOLOGY_MASK_B;
+ bool retval = false;
+
+ if (! mIsInit)
+ {
+ ALOGE ("%s: not init", fn);
+ return false;
+ }
+
+ if (mCurrentRouteSelection == SecElemRoute)
+ {
+ ALOGE ("%s: already sec elem route", fn);
+ return true;
+ }
+
+ if (mActiveEeHandle == NFA_HANDLE_INVALID)
+ {
+ ALOGE ("%s: invalid EE handle", fn);
+ return false;
+ }
+
+ adjustRoutes (SecElemRoute);
+
+ {
+ unsigned long num = 0;
+ if (GetNumValue("UICC_LISTEN_TECH_MASK", &num, sizeof(num)))
+ tech_mask = num;
+ ALOGD ("%s: start UICC listen; h=0x%X; tech mask=0x%X", fn, mActiveEeHandle, tech_mask);
+ SyncEventGuard guard (mUiccListenEvent);
+ nfaStat = NFA_CeConfigureUiccListenTech (mActiveEeHandle, tech_mask);
+ if (nfaStat == NFA_STATUS_OK)
+ {
+ mUiccListenEvent.wait ();
+ retval = true;
+ }
+ else
+ ALOGE ("%s: fail to start UICC listen", fn);
+ }
+
+ ALOGD ("%s: exit; ok=%u", fn, retval);
+ return retval;
+}
+
+
+/*******************************************************************************
+**
+** Function: routeToDefault
+**
+** Description: Adjust controller's listen-mode routing table so transactions
+** are routed to the default destination.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool SecureElement::routeToDefault ()
+{
+ static const char fn [] = "SecureElement::routeToDefault";
+ tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
+ bool retval = false;
+
+ ALOGD ("%s: enter", fn);
+ if (! mIsInit)
+ {
+ ALOGE ("%s: not init", fn);
+ return false;
+ }
+
+ if (mCurrentRouteSelection == DefaultRoute)
+ {
+ ALOGD ("%s: already default route", fn);
+ return true;
+ }
+
+ if (mActiveEeHandle != NFA_HANDLE_INVALID)
+ {
+ ALOGD ("%s: stop UICC listen; EE h=0x%X", fn, mActiveEeHandle);
+ SyncEventGuard guard (mUiccListenEvent);
+ nfaStat = NFA_CeConfigureUiccListenTech (mActiveEeHandle, 0);
+ if (nfaStat == NFA_STATUS_OK)
+ {
+ mUiccListenEvent.wait ();
+ retval = true;
+ }
+ else
+ ALOGE ("%s: fail to stop UICC listen", fn);
+ }
+ else
+ retval = true;
+
+ adjustRoutes (DefaultRoute);
+
+ ALOGD ("%s: exit; ok=%u", fn, retval);
+ return retval;
+}
+
+
+/*******************************************************************************
+**
+** Function: isBusy
+**
+** Description: Whether controller is routing listen-mode events to
+** secure elements or a pipe is connected.
+**
+** Returns: True if either case is true.
+**
+*******************************************************************************/
+bool SecureElement::isBusy ()
+{
+ bool retval = (mCurrentRouteSelection == SecElemRoute) || mIsPiping;
+ ALOGD ("SecureElement::isBusy: %u", retval);
+ return retval;
+}
+
diff --git a/nci/jni/SecureElement.h b/nci/jni/SecureElement.h
new file mode 100755
index 0000000..1758590
--- /dev/null
+++ b/nci/jni/SecureElement.h
@@ -0,0 +1,607 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+/*
+ * Communicate with secure elements that are attached to the NFC
+ * controller.
+ */
+#pragma once
+#include "SyncEvent.h"
+#include "DataQueue.h"
+#include "NfcJniUtil.h"
+#include "RouteDataSet.h"
+extern "C"
+{
+ #include "nfa_ee_api.h"
+ #include "nfa_hci_api.h"
+ #include "nfa_hci_defs.h"
+ #include "nfa_ce_api.h"
+}
+
+
+class SecureElement
+{
+public:
+ tNFA_HANDLE mActiveEeHandle;
+
+
+ /*******************************************************************************
+ **
+ ** Function: getInstance
+ **
+ ** Description: Get the SecureElement singleton object.
+ **
+ ** Returns: SecureElement object.
+ **
+ *******************************************************************************/
+ static SecureElement& getInstance ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: initialize
+ **
+ ** Description: Initialize all member variables.
+ ** native: Native data.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool initialize (nfc_jni_native_data* native);
+
+
+ /*******************************************************************************
+ **
+ ** Function: finalize
+ **
+ ** Description: Release all resources.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void finalize ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: getListOfEeHandles
+ **
+ ** Description: Get the list of handles of all execution environments.
+ ** e: Java Virtual Machine.
+ **
+ ** Returns: List of handles of all execution environments.
+ **
+ *******************************************************************************/
+ jintArray getListOfEeHandles (JNIEnv* e);
+
+
+ /*******************************************************************************
+ **
+ ** Function: activate
+ **
+ ** Description: Turn on the secure element.
+ ** seID: ID of secure element.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool activate (jint seID);
+
+
+ /*******************************************************************************
+ **
+ ** Function: deactivate
+ **
+ ** Description: Turn off the secure element.
+ ** seID: ID of secure element.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool deactivate (jint seID);
+
+
+ /*******************************************************************************
+ **
+ ** Function: connectEE
+ **
+ ** Description: Connect to the execution environment.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool connectEE ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: disconnectEE
+ **
+ ** Description: Disconnect from the execution environment.
+ ** seID: ID of secure element.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool disconnectEE (jint seID);
+
+
+ /*******************************************************************************
+ **
+ ** Function: transceive
+ **
+ ** Description: Send data to the secure element; read it's response.
+ ** xmitBuffer: Data to transmit.
+ ** xmitBufferSize: Length of data.
+ ** recvBuffer: Buffer to receive response.
+ ** recvBufferMaxSize: Maximum size of buffer.
+ ** recvBufferActualSize: Actual length of response.
+ ** timeoutMillisec: timeout in millisecond
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool transceive (UINT8* xmitBuffer, INT32 xmitBufferSize, UINT8* recvBuffer,
+ INT32 recvBufferMaxSize, INT32& recvBufferActualSize, INT32 timeoutMillisec);
+
+ /*******************************************************************************
+ **
+ ** Function: notifyListenModeState
+ **
+ ** Description: Notify the NFC service about whether the SE was activated
+ ** in listen mode.
+ ** isActive: Whether the secure element is activated.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void notifyListenModeState (bool isActivated);
+
+ /*******************************************************************************
+ **
+ ** Function: notifyRfFieldEvent
+ **
+ ** Description: Notify the NFC service about RF field events from the stack.
+ ** isActive: Whether any secure element is activated.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void notifyRfFieldEvent (bool isActive);
+
+
+ /*******************************************************************************
+ **
+ ** Function: storeUiccInfo
+ **
+ ** Description: Store a copy of the execution environment information from the stack.
+ ** info: execution environment information.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void storeUiccInfo (tNFA_EE_DISCOVER_REQ& info);
+
+
+ /*******************************************************************************
+ **
+ ** Function: getUiccId
+ **
+ ** Description: Get the ID of the secure element.
+ ** eeHandle: Handle to the secure element.
+ ** uid: Array to receive the ID.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool getUiccId (tNFA_HANDLE eeHandle, jbyteArray& uid);
+
+
+ /*******************************************************************************
+ **
+ ** Function: getTechnologyList
+ **
+ ** Description: Get all the technologies supported by a secure element.
+ ** eeHandle: Handle of secure element.
+ ** techList: List to receive the technologies.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool getTechnologyList (tNFA_HANDLE eeHandle, jintArray& techList);
+
+
+ /*******************************************************************************
+ **
+ ** Function: notifyTransactionListenersOfAid
+ **
+ ** Description: Notify the NFC service about a transaction event from secure element.
+ ** aid: Buffer contains application ID.
+ ** aidLen: Length of application ID.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void notifyTransactionListenersOfAid (const UINT8* aid, UINT8 aidLen);
+
+
+ /*******************************************************************************
+ **
+ ** Function: notifyTransactionListenersOfTlv
+ **
+ ** Description: Notify the NFC service about a transaction event from secure element.
+ ** The type-length-value contains AID and parameter.
+ ** tlv: type-length-value encoded in Basic Encoding Rule.
+ ** tlvLen: Length tlv.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void notifyTransactionListenersOfTlv (const UINT8* tlv, UINT8 tlvLen);
+
+
+ /*******************************************************************************
+ **
+ ** Function: connectionEventHandler
+ **
+ ** Description: Receive card-emulation related events from stack.
+ ** event: Event code.
+ ** eventData: Event data.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void connectionEventHandler (UINT8 event, tNFA_CONN_EVT_DATA* eventData);
+
+
+ /*******************************************************************************
+ **
+ ** Function: applyRoutes
+ **
+ ** Description: Read route data from XML and apply them again
+ ** to every secure element.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void applyRoutes ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: setActiveSeOverride
+ **
+ ** Description: Specify which secure element to turn on.
+ ** activeSeOverride: ID of secure element
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void setActiveSeOverride (UINT8 activeSeOverride);
+
+
+ /*******************************************************************************
+ **
+ ** Function: routeToSecureElement
+ **
+ ** Description: Adjust controller's listen-mode routing table so transactions
+ ** are routed to the secure elements as specified in route.xml.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool routeToSecureElement ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: routeToDefault
+ **
+ ** Description: Adjust controller's listen-mode routing table so transactions
+ ** are routed to the default destination specified in route.xml.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool routeToDefault ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: isBusy
+ **
+ ** Description: Whether NFC controller is routing listen-mode events or a pipe is connected.
+ **
+ ** Returns: True if either case is true.
+ **
+ *******************************************************************************/
+ bool isBusy ();
+
+
+ /*******************************************************************************
+ **
+ ** Function getActualNumEe
+ **
+ ** Description Returns number of secure elements we know about.
+ **
+ ** Returns Number of secure elements we know about.
+ **
+ *******************************************************************************/
+ UINT8 getActualNumEe();
+
+
+ /*******************************************************************************
+ **
+ ** Function getSeVerInfo
+ **
+ ** Description Gets version information and id for a secure element. The
+ ** seIndex parmeter is the zero based index of the secure
+ ** element to get verion info for. The version infommation
+ ** is returned as a string int the verInfo parameter.
+ **
+ ** Returns ture on success, false on failure
+ **
+ *******************************************************************************/
+ bool getSeVerInfo(int seIndex, char * verInfo, int verInfoSz, UINT8 * seid);
+
+
+ /*******************************************************************************
+ **
+ ** Function: isActivatedInListenMode
+ **
+ ** Description: Can be used to determine if the SE is activated in listen mode
+ **
+ ** Returns: True if the SE is activated in listen mode
+ **
+ *******************************************************************************/
+ bool isActivatedInListenMode();
+
+ /*******************************************************************************
+ **
+ ** Function: isRfFieldOn
+ **
+ ** Description: Can be used to determine if the SE is in an RF field
+ **
+ ** Returns: True if the SE is activated in an RF field
+ **
+ *******************************************************************************/
+ bool isRfFieldOn();
+
+private:
+ static const unsigned int MAX_RESPONSE_SIZE = 1024;
+ enum RouteSelection {NoRoute, DefaultRoute, SecElemRoute};
+ static const int MAX_NUM_EE = 5; //max number of EE's
+ static const UINT8 STATIC_PIPE_0x70 = 0x70; //Broadcom's proprietary static pipe
+ static const UINT8 STATIC_PIPE_0x71 = 0x71; //Broadcom's proprietary static pipe
+ static const UINT8 EVT_SEND_DATA = 0x10; //see specification ETSI TS 102 622 v9.0.0 (Host Controller Interface); section 9.3.3.3
+ static const tNFA_HANDLE EE_HANDLE_0xF3 = 0x4F3; //handle to secure element in slot 0
+ static const tNFA_HANDLE EE_HANDLE_0xF4 = 0x4F4; //handle to secure element in slot 1
+ static SecureElement sSecElem;
+ static const char* APP_NAME;
+
+ UINT8 mDestinationGate; //destination gate of the UICC
+ tNFA_HANDLE mNfaHciHandle; //NFA handle to NFA's HCI component
+ nfc_jni_native_data* mNativeData;
+ bool mIsInit; // whether EE is initialized
+ UINT8 mActualNumEe; // actual number of EE's reported by the stack
+ UINT8 mNumEePresent; // actual number of usable EE's
+ bool mbNewEE;
+ UINT8 mNewPipeId;
+ UINT8 mNewSourceGate;
+ UINT16 mActiveSeOverride; // active "enable" seid, 0 means activate all SEs
+ tNFA_STATUS mCommandStatus; //completion status of the last command
+ bool mIsPiping; //is a pipe connected to the controller?
+ RouteSelection mCurrentRouteSelection;
+ int mActualResponseSize; //number of bytes in the response received from secure element
+ bool mUseOberthurWarmReset; //whether to use warm-reset command
+ bool mActivatedInListenMode; // whether we're activated in listen mode
+ UINT8 mOberthurWarmResetCommand; //warm-reset command byte
+ tNFA_EE_INFO mEeInfo [MAX_NUM_EE]; //actual size stored in mActualNumEe
+ tNFA_EE_DISCOVER_REQ mUiccInfo;
+ tNFA_HCI_GET_GATE_PIPE_LIST mHciCfg;
+ SyncEvent mEeRegisterEvent;
+ SyncEvent mHciRegisterEvent;
+ SyncEvent mEeSetModeEvent;
+ SyncEvent mPipeListEvent;
+ SyncEvent mCreatePipeEvent;
+ SyncEvent mPipeOpenedEvent;
+ SyncEvent mAllocateGateEvent;
+ SyncEvent mDeallocateGateEvent;
+ SyncEvent mRoutingEvent;
+ SyncEvent mUiccInfoEvent;
+ SyncEvent mUiccListenEvent;
+ SyncEvent mAidAddRemoveEvent;
+ SyncEvent mTransceiveEvent;
+ SyncEvent mVerInfoEvent;
+ SyncEvent mRegistryEvent;
+ UINT8 mVerInfo [3];
+ UINT8 mResponseData [MAX_RESPONSE_SIZE];
+ RouteDataSet mRouteDataSet; //routing data
+ std::vector<std::string> mUsedAids; //AID's that are used in current routes
+ UINT8 mAidForEmptySelect[NCI_MAX_AID_LEN+1];
+ Mutex mMutex; // protects fields below
+ bool mRfFieldIsOn; // last known RF field state
+ struct timespec mLastRfFieldToggle; // last time RF field went off
+ /*******************************************************************************
+ **
+ ** Function: SecureElement
+ **
+ ** Description: Initialize member variables.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ SecureElement ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: ~SecureElement
+ **
+ ** Description: Release all resources.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ ~SecureElement ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: nfaEeCallback
+ **
+ ** Description: Receive execution environment-related events from stack.
+ ** event: Event code.
+ ** eventData: Event data.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ static void nfaEeCallback (tNFA_EE_EVT event, tNFA_EE_CBACK_DATA* eventData);
+
+
+ /*******************************************************************************
+ **
+ ** Function: nfaHciCallback
+ **
+ ** Description: Receive Host Controller Interface-related events from stack.
+ ** event: Event code.
+ ** eventData: Event data.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ static void nfaHciCallback (tNFA_HCI_EVT event, tNFA_HCI_EVT_DATA* eventData);
+
+
+ /*******************************************************************************
+ **
+ ** Function: findEeByHandle
+ **
+ ** Description: Find information about an execution environment.
+ ** eeHandle: Handle to execution environment.
+ **
+ ** Returns: Information about an execution environment.
+ **
+ *******************************************************************************/
+ tNFA_EE_INFO *findEeByHandle (tNFA_HANDLE eeHandle);
+
+
+ /*******************************************************************************
+ **
+ ** Function: findUiccByHandle
+ **
+ ** Description: Find information about an execution environment.
+ ** eeHandle: Handle of the execution environment.
+ **
+ ** Returns: Information about the execution environment.
+ **
+ *******************************************************************************/
+ tNFA_EE_DISCOVER_INFO *findUiccByHandle (tNFA_HANDLE eeHandle);
+
+
+ /*******************************************************************************
+ **
+ ** Function: getDefaultEeHandle
+ **
+ ** Description: Get the handle to the execution environment.
+ **
+ ** Returns: Handle to the execution environment.
+ **
+ *******************************************************************************/
+ tNFA_HANDLE getDefaultEeHandle ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: adjustRoutes
+ **
+ ** Description: Adjust routes in the controller's listen-mode routing table.
+ ** selection: which set of routes to configure the controller.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void adjustRoutes (RouteSelection selection);
+
+
+ /*******************************************************************************
+ **
+ ** Function: adjustProtocolRoutes
+ **
+ ** Description: Adjust default routing based on protocol in NFC listen mode.
+ ** isRouteToEe: Whether routing to EE (true) or host (false).
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void adjustProtocolRoutes (RouteDataSet::Database* db, RouteSelection routeSelection);
+
+
+ /*******************************************************************************
+ **
+ ** Function: adjustTechnologyRoutes
+ **
+ ** Description: Adjust default routing based on technology in NFC listen mode.
+ ** isRouteToEe: Whether routing to EE (true) or host (false).
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void adjustTechnologyRoutes (RouteDataSet::Database* db, RouteSelection routeSelection);
+
+
+ /*******************************************************************************
+ **
+ ** Function: getEeInfo
+ **
+ ** Description: Get latest information about execution environments from stack.
+ **
+ ** Returns: True if at least 1 EE is available.
+ **
+ *******************************************************************************/
+ bool getEeInfo ();
+
+ /*******************************************************************************
+ **
+ ** Function: eeStatusToString
+ **
+ ** Description: Convert status code to status text.
+ ** status: Status code
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ static const char* eeStatusToString (UINT8 status);
+
+
+ /*******************************************************************************
+ **
+ ** Function: encodeAid
+ **
+ ** Description: Encode AID in type-length-value using Basic Encoding Rule.
+ ** tlv: Buffer to store TLV.
+ ** tlvMaxLen: TLV buffer's maximum length.
+ ** tlvActualLen: TLV buffer's actual length.
+ ** aid: Buffer of Application ID.
+ ** aidLen: Aid buffer's actual length.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool encodeAid (UINT8* tlv, UINT16 tlvMaxLen, UINT16& tlvActualLen, const UINT8* aid, UINT8 aidLen);
+};
+
diff --git a/nci/jni/SyncEvent.h b/nci/jni/SyncEvent.h
new file mode 100644
index 0000000..5fd389e
--- /dev/null
+++ b/nci/jni/SyncEvent.h
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+/*
+ * Synchronize two or more threads using a condition variable and a mutex.
+ */
+#pragma once
+#include "CondVar.h"
+#include "Mutex.h"
+
+
+class SyncEvent
+{
+public:
+ /*******************************************************************************
+ **
+ ** Function: ~SyncEvent
+ **
+ ** Description: Cleanup all resources.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ ~SyncEvent ()
+ {
+ }
+
+
+ /*******************************************************************************
+ **
+ ** Function: start
+ **
+ ** Description: Start a synchronization operation.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ void start ()
+ {
+ mMutex.lock ();
+ }
+
+
+ /*******************************************************************************
+ **
+ ** Function: wait
+ **
+ ** Description: Block the thread and wait for the event to occur.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ void wait ()
+ {
+ mCondVar.wait (mMutex);
+ }
+
+
+ /*******************************************************************************
+ **
+ ** Function: wait
+ **
+ ** Description: Block the thread and wait for the event to occur.
+ ** millisec: Timeout in milliseconds.
+ **
+ ** Returns: True if wait is successful; false if timeout occurs.
+ **
+ *******************************************************************************/
+ bool wait (long millisec)
+ {
+ bool retVal = mCondVar.wait (mMutex, millisec);
+ return retVal;
+ }
+
+
+ /*******************************************************************************
+ **
+ ** Function: notifyOne
+ **
+ ** Description: Notify a blocked thread that the event has occured. Unblocks it.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ void notifyOne ()
+ {
+ mCondVar.notifyOne ();
+ }
+
+
+ /*******************************************************************************
+ **
+ ** Function: end
+ **
+ ** Description: End a synchronization operation.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ void end ()
+ {
+ mMutex.unlock ();
+ }
+
+private:
+ CondVar mCondVar;
+ Mutex mMutex;
+};
+
+
+/*****************************************************************************/
+/*****************************************************************************/
+
+
+/*****************************************************************************
+**
+** Name: SyncEventGuard
+**
+** Description: Automatically start and end a synchronization event.
+**
+*****************************************************************************/
+class SyncEventGuard
+{
+public:
+ /*******************************************************************************
+ **
+ ** Function: SyncEventGuard
+ **
+ ** Description: Start a synchronization operation.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ SyncEventGuard (SyncEvent& event)
+ : mEvent (event)
+ {
+ event.start (); //automatically start operation
+ };
+
+
+ /*******************************************************************************
+ **
+ ** Function: ~SyncEventGuard
+ **
+ ** Description: End a synchronization operation.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ ~SyncEventGuard ()
+ {
+ mEvent.end (); //automatically end operation
+ };
+
+private:
+ SyncEvent& mEvent;
+};
+