summaryrefslogtreecommitdiffstats
path: root/nci
diff options
context:
space:
mode:
authorMartijn Coenen <maco@google.com>2012-10-04 16:52:51 -0700
committerMartijn Coenen <maco@google.com>2012-10-11 15:17:24 -0700
commita949c74321b17f8ef1c93692064969f60815c7e4 (patch)
tree4cc361632b88b096357b1d51f4466eece1423ab3 /nci
parentae1b16cf81e49a438b7a86efcdd8d83c1c0666d1 (diff)
downloadpackages_apps_nfc-a949c74321b17f8ef1c93692064969f60815c7e4.zip
packages_apps_nfc-a949c74321b17f8ef1c93692064969f60815c7e4.tar.gz
packages_apps_nfc-a949c74321b17f8ef1c93692064969f60815c7e4.tar.bz2
Fast-fail SE open if it's activated in listen mode.
Users of the NFC-extras API usually want to talk to the SE once it has completed a transaction. The hard part is knowing when it is safe to connect to the SE, as it will break the connection to any reader. And when relinquishing the connection to the SE, the reader may find the device again and process another transaction. This patch adds the following two conditions for allowing to open the SE from the DH: 1) The SE may not be activated in listen mode 2) The RF field must have been off for at least 50 ms Bug: 7275484 Change-Id: Ibde32a8e2aef045c17ab76ef08c72f96edfedaef
Diffstat (limited to 'nci')
-rw-r--r--nci/jni/JavaClassConstants.h2
-rwxr-xr-xnci/jni/NativeNfcManager.cpp47
-rwxr-xr-xnci/jni/NativeSecureElement.cpp20
-rwxr-xr-xnci/jni/SecureElement.cpp127
-rwxr-xr-xnci/jni/SecureElement.h40
-rwxr-xr-xnci/src/com/android/nfc/dhimpl/NativeNfcManager.java8
6 files changed, 227 insertions, 17 deletions
diff --git a/nci/jni/JavaClassConstants.h b/nci/jni/JavaClassConstants.h
index 64244c3..30deca9 100644
--- a/nci/jni/JavaClassConstants.h
+++ b/nci/jni/JavaClassConstants.h
@@ -24,6 +24,8 @@ namespace android
extern jmethodID gCachedNfcManagerNotifyLlcpLinkDeactivated;
extern jmethodID gCachedNfcManagerNotifySeFieldActivated;
extern jmethodID gCachedNfcManagerNotifySeFieldDeactivated;
+ extern jmethodID gCachedNfcManagerNotifySeListenActivated;
+ extern jmethodID gCachedNfcManagerNotifySeListenDeactivated;
extern const char* gNativeP2pDeviceClassName;
extern const char* gNativeLlcpServiceSocketClassName;
diff --git a/nci/jni/NativeNfcManager.cpp b/nci/jni/NativeNfcManager.cpp
index eadca87..81bb6b2 100755
--- a/nci/jni/NativeNfcManager.cpp
+++ b/nci/jni/NativeNfcManager.cpp
@@ -78,6 +78,8 @@ namespace android
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";
@@ -112,6 +114,7 @@ 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;
@@ -304,7 +307,18 @@ static void nfaConnectionCallback (UINT8 connEvent, tNFA_CONN_EVT_DATA* eventDat
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)
{
@@ -316,7 +330,7 @@ static void nfaConnectionCallback (UINT8 connEvent, tNFA_CONN_EVT_DATA* eventDat
if (isListenMode(eventData->activated))
{
sSeRfActive = true;
- SecureElement::getInstance().notifyRfFieldEvent (true);
+ SecureElement::getInstance().notifyListenModeState (true);
}
}
@@ -338,13 +352,30 @@ static void nfaConnectionCallback (UINT8 connEvent, tNFA_CONN_EVT_DATA* eventDat
// 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 (sSeRfActive
- && ((eventData->deactivated.type == NFA_DEACTIVATE_TYPE_IDLE)
- || (eventData->deactivated.type == NFA_DEACTIVATE_TYPE_DISCOVERY)))
+ if ((eventData->deactivated.type == NFA_DEACTIVATE_TYPE_IDLE)
+ || (eventData->deactivated.type == NFA_DEACTIVATE_TYPE_DISCOVERY))
{
- sSeRfActive = false;
- SecureElement::getInstance().notifyRfFieldEvent (false);
+ 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
@@ -513,6 +544,10 @@ static jboolean nfcManager_initNativeStruc (JNIEnv* e, jobject o)
"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");
diff --git a/nci/jni/NativeSecureElement.cpp b/nci/jni/NativeSecureElement.cpp
index 104d4ea..1a2a73a 100755
--- a/nci/jni/NativeSecureElement.cpp
+++ b/nci/jni/NativeSecureElement.cpp
@@ -44,24 +44,34 @@ static jint nativeNfcSecureElement_doOpenSecureElementConnection (JNIEnv* e, job
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 (! SecureElement::getInstance().isBusy())
- stat = SecureElement::getInstance().activate(0);
+ if (! se.isBusy())
+ stat = se.activate(0);
if (stat)
{
//establish a pipe to sec elem
- stat = SecureElement::getInstance().connectEE();
+ stat = se.connectEE();
if (stat)
- secElemHandle = SecureElement::getInstance().mActiveEeHandle;
+ secElemHandle = se.mActiveEeHandle;
else
- SecureElement::getInstance().deactivate (0);
+ se.deactivate (0);
}
//if code fails to connect to the secure element, and nothing is active, then
diff --git a/nci/jni/SecureElement.cpp b/nci/jni/SecureElement.cpp
index 1004bb4..f6b2721 100755
--- a/nci/jni/SecureElement.cpp
+++ b/nci/jni/SecureElement.cpp
@@ -76,13 +76,16 @@ SecureElement::SecureElement ()
mCurrentRouteSelection (NoRoute),
mActualResponseSize(0),
mUseOberthurWarmReset (false),
- mOberthurWarmResetCommand (3)
+ 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));
}
@@ -323,6 +326,70 @@ bool SecureElement::getEeInfo()
/*******************************************************************************
**
+** 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.
@@ -939,6 +1006,48 @@ TheEnd:
/*******************************************************************************
**
+** 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.
@@ -961,17 +1070,27 @@ void SecureElement::notifyRfFieldEvent (bool isActive)
return;
}
- if (isActive)
+ 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
+ }
+ 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);
}
diff --git a/nci/jni/SecureElement.h b/nci/jni/SecureElement.h
index 8339a29..1758590 100755
--- a/nci/jni/SecureElement.h
+++ b/nci/jni/SecureElement.h
@@ -157,6 +157,18 @@ public:
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);
/*******************************************************************************
**
@@ -346,6 +358,28 @@ public:
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};
@@ -373,6 +407,7 @@ private:
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;
@@ -397,7 +432,9 @@ private:
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
@@ -538,7 +575,6 @@ private:
*******************************************************************************/
bool getEeInfo ();
-
/*******************************************************************************
**
** Function: eeStatusToString
diff --git a/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java b/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java
index 921e266..40b9347 100755
--- a/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java
+++ b/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java
@@ -336,6 +336,14 @@ public class NativeNfcManager implements DeviceHost {
mListener.onRemoteFieldDeactivated();
}
+ private void notifySeListenActivated() {
+ mListener.onSeListenActivated();
+ }
+
+ private void notifySeListenDeactivated() {
+ mListener.onSeListenDeactivated();
+ }
+
private void notifySeApduReceived(byte[] apdu) {
mListener.onSeApduReceived(apdu);
}