diff options
author | Martijn Coenen <maco@google.com> | 2012-10-04 16:52:51 -0700 |
---|---|---|
committer | Martijn Coenen <maco@google.com> | 2012-10-11 15:17:24 -0700 |
commit | a949c74321b17f8ef1c93692064969f60815c7e4 (patch) | |
tree | 4cc361632b88b096357b1d51f4466eece1423ab3 /nci | |
parent | ae1b16cf81e49a438b7a86efcdd8d83c1c0666d1 (diff) | |
download | packages_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.h | 2 | ||||
-rwxr-xr-x | nci/jni/NativeNfcManager.cpp | 47 | ||||
-rwxr-xr-x | nci/jni/NativeSecureElement.cpp | 20 | ||||
-rwxr-xr-x | nci/jni/SecureElement.cpp | 127 | ||||
-rwxr-xr-x | nci/jni/SecureElement.h | 40 | ||||
-rwxr-xr-x | nci/src/com/android/nfc/dhimpl/NativeNfcManager.java | 8 |
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); } |