/* * 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 <android-base/stringprintf.h> #include <base/logging.h> #include <cutils/properties.h> #include <errno.h> #include <nativehelper/ScopedLocalRef.h> #include <nativehelper/ScopedPrimitiveArray.h> #include <nativehelper/ScopedUtfChars.h> #include <semaphore.h> #include "HciEventManager.h" #include "JavaClassConstants.h" #include "NfcAdaptation.h" #include "NfcJniUtil.h" #include "NfcTag.h" #include "PeerToPeer.h" #include "Pn544Interop.h" #include "PowerSwitch.h" #include "RoutingManager.h" #include "SyncEvent.h" #include "nfc_config.h" #include "ce_api.h" #include "nfa_api.h" #include "nfa_ee_api.h" #include "nfa_p2p_api.h" #include "nfc_brcm_defs.h" #include "phNxpExtns.h" #include "rw_api.h" using android::base::StringPrintf; extern tNFA_DM_DISC_FREQ_CFG* p_nfa_dm_rf_disc_freq_cfg; // defined in stack namespace android { extern bool gIsTagDeactivating; extern bool gIsSelectingRfInterface; extern void nativeNfcTag_doTransceiveStatus(tNFA_STATUS status, uint8_t* buf, uint32_t buflen); extern void nativeNfcTag_notifyRfTimeout(); extern void nativeNfcTag_doConnectStatus(jboolean is_connect_ok); extern void nativeNfcTag_doDeactivateStatus(int status); extern void nativeNfcTag_doWriteStatus(jboolean is_write_ok); extern jboolean nativeNfcTag_doDisconnect(JNIEnv*, jobject); 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_setRfInterface(tNFA_INTF_TYPE rfInterface); extern void nativeNfcTag_abortWaits(); extern void nativeLlcpConnectionlessSocket_abortWait(); extern void nativeNfcTag_registerNdefTypeHandler(); extern void nativeNfcTag_acquireRfInterfaceMutexLock(); extern void nativeNfcTag_releaseRfInterfaceMutexLock(); extern void nativeLlcpConnectionlessSocket_receiveData(uint8_t* data, uint32_t len, uint32_t remote_sap); } // namespace android /***************************************************************************** ** ** public variables and functions ** *****************************************************************************/ bool gActivated = false; SyncEvent gDeactivatedEvent; SyncEvent sNfaSetPowerSubState; namespace android { jmethodID gCachedNfcManagerNotifyNdefMessageListeners; jmethodID gCachedNfcManagerNotifyTransactionListeners; jmethodID gCachedNfcManagerNotifyLlcpLinkActivation; jmethodID gCachedNfcManagerNotifyLlcpLinkDeactivated; jmethodID gCachedNfcManagerNotifyLlcpFirstPacketReceived; jmethodID gCachedNfcManagerNotifyHostEmuActivated; jmethodID gCachedNfcManagerNotifyHostEmuData; jmethodID gCachedNfcManagerNotifyHostEmuDeactivated; jmethodID gCachedNfcManagerNotifyRfFieldActivated; jmethodID gCachedNfcManagerNotifyRfFieldDeactivated; 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"; void doStartupConfig(); void startStopPolling(bool isStartPolling); void startRfDiscovery(bool isStart); bool isDiscoveryStarted(); } // namespace android /***************************************************************************** ** ** private variables and functions ** *****************************************************************************/ namespace android { static jint sLastError = ERROR_BUFFER_TOO_SMALL; 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 SyncEvent sNfaGetConfigEvent; // event for Get_Config.... static bool sIsNfaEnabled = false; static bool sDiscoveryEnabled = false; // is polling or listening static bool sPollingEnabled = 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 sReaderModeEnabled = false; // whether we're only reading tags, not allowing P2p/card emu static bool sP2pEnabled = false; static bool sP2pActive = false; // whether p2p was last active static bool sAbortConnlessWait = false; static jint sLfT3tMax = 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_V | NFA_TECHNOLOGY_MASK_B_PRIME | \ NFA_TECHNOLOGY_MASK_A_ACTIVE | NFA_TECHNOLOGY_MASK_F_ACTIVE | \ NFA_TECHNOLOGY_MASK_KOVIO) #define DEFAULT_DISCOVERY_DURATION 500 #define READER_MODE_DISCOVERY_DURATION 200 static void nfaConnectionCallback(uint8_t event, tNFA_CONN_EVT_DATA* eventData); static void nfaDeviceManagementCallback(uint8_t event, tNFA_DM_CBACK_DATA* eventData); static bool isPeerToPeer(tNFA_ACTIVATED& activated); static bool isListenMode(tNFA_ACTIVATED& activated); static void enableDisableLptd(bool enable); static tNFA_STATUS stopPolling_rfDiscoveryDisabled(); static tNFA_STATUS startPolling_rfDiscoveryDisabled( tNFA_TECHNOLOGY_MASK tech_mask); static void nfcManager_doSetScreenState(JNIEnv* e, jobject o, jint screen_state_mask); static uint16_t sCurrentConfigLen; static uint8_t sConfig[256]; static int prevScreenState = NFA_SCREEN_STATE_OFF_LOCKED; static int NFA_SCREEN_POLLING_TAG_MASK = 0x10; static bool gIsDtaEnabled = false; ///////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////// bool nfc_debug_enabled; namespace { void initializeGlobalDebugEnabledFlag() { nfc_debug_enabled = (NfcConfig::getUnsigned(NAME_NFC_DEBUG_ENABLED, 1) != 0) ? true : false; char valueStr[PROPERTY_VALUE_MAX] = {0}; int len = property_get("nfc.debug_enabled", valueStr, ""); if (len > 0) { unsigned debug_enabled = 1; // let Android property override .conf variable sscanf(valueStr, "%u", &debug_enabled); nfc_debug_enabled = (debug_enabled == 0) ? false : true; } DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: level=%u", __func__, nfc_debug_enabled); } } // namespace /******************************************************************************* ** ** 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 == NCI_DISCOVER_NTF_MORE) { // there is more discovery notification coming return; } bool isP2p = NfcTag::getInstance().isP2pDiscovered(); if (!sReaderModeEnabled && 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_t connEvent, tNFA_CONN_EVT_DATA* eventData) { tNFA_STATUS status = NFA_STATUS_FAILED; DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: event= %u", __func__, connEvent); switch (connEvent) { case NFA_POLL_ENABLED_EVT: // whether polling successfully started { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%s: NFA_POLL_ENABLED_EVT: status = %u", __func__, eventData->status); SyncEventGuard guard(sNfaEnableDisablePollingEvent); sNfaEnableDisablePollingEvent.notifyOne(); } break; case NFA_POLL_DISABLED_EVT: // Listening/Polling stopped { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: NFA_POLL_DISABLED_EVT: status = %u", __func__, eventData->status); SyncEventGuard guard(sNfaEnableDisablePollingEvent); sNfaEnableDisablePollingEvent.notifyOne(); } break; case NFA_RF_DISCOVERY_STARTED_EVT: // RF Discovery started { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: NFA_RF_DISCOVERY_STARTED_EVT: status = %u", __func__, eventData->status); SyncEventGuard guard(sNfaEnableDisablePollingEvent); sNfaEnableDisablePollingEvent.notifyOne(); } break; case NFA_RF_DISCOVERY_STOPPED_EVT: // RF Discovery stopped event { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: NFA_RF_DISCOVERY_STOPPED_EVT: status = %u", __func__, eventData->status); SyncEventGuard guard(sNfaEnableDisablePollingEvent); sNfaEnableDisablePollingEvent.notifyOne(); } break; case NFA_DISC_RESULT_EVT: // NFC link/protocol discovery notificaiton status = eventData->disc_result.status; DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%s: NFA_DISC_RESULT_EVT: status = %d", __func__, status); if (status != NFA_STATUS_OK) { LOG(ERROR) << StringPrintf("%s: NFA_DISC_RESULT_EVT error: status = %d", __func__, 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 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%s: NFA_SELECT_RESULT_EVT: status = %d, gIsSelectingRfInterface = " "%d, " "sIsDisabling=%d", __func__, eventData->status, gIsSelectingRfInterface, sIsDisabling); if (sIsDisabling) break; if (eventData->status != NFA_STATUS_OK) { if (gIsSelectingRfInterface) { nativeNfcTag_doConnectStatus(false); } LOG(ERROR) << StringPrintf( "%s: NFA_SELECT_RESULT_EVT error: status = %d", __func__, eventData->status); NFA_Deactivate(FALSE); } break; case NFA_DEACTIVATE_FAIL_EVT: DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: NFA_DEACTIVATE_FAIL_EVT: status = %d", __func__, eventData->status); break; case NFA_ACTIVATED_EVT: // NFC link/protocol activated DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%s: NFA_ACTIVATED_EVT: gIsSelectingRfInterface=%d, sIsDisabling=%d", __func__, gIsSelectingRfInterface, sIsDisabling); if ((eventData->activated.activate_ntf.protocol != NFA_PROTOCOL_NFC_DEP) && (!isListenMode(eventData->activated))) { nativeNfcTag_setRfInterface( (tNFA_INTF_TYPE)eventData->activated.activate_ntf.intf_param.type); } if (EXTNS_GetConnectFlag() == TRUE) { NfcTag::getInstance().setActivationState(); nativeNfcTag_doConnectStatus(true); break; } NfcTag::getInstance().setActive(true); if (sIsDisabling || !sIsNfaEnabled) break; gActivated = true; NfcTag::getInstance().setActivationState(); if (gIsSelectingRfInterface) { nativeNfcTag_doConnectStatus(true); break; } nativeNfcTag_resetPresenceCheck(); if (isPeerToPeer(eventData->activated)) { if (sReaderModeEnabled) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%s: ignoring peer target in reader mode.", __func__); NFA_Deactivate(FALSE); break; } sP2pActive = true; DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: NFA_ACTIVATED_EVT; is p2p", __func__); if (NFC_GetNCIVersion() == NCI_VERSION_1_0) { // Disable RF field events in case of p2p uint8_t nfa_disable_rf_events[] = {0x00}; DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: Disabling RF field events", __func__); status = NFA_SetConfig(NCI_PARAM_ID_RF_FIELD_INFO, sizeof(nfa_disable_rf_events), &nfa_disable_rf_events[0]); if (status == NFA_STATUS_OK) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: Disabled RF field events", __func__); } else { LOG(ERROR) << StringPrintf("%s: Failed to disable RF field events", __func__); } } } 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 an SE transaction. // Send the RF Event. if (isListenMode(eventData->activated)) { sSeRfActive = true; } } break; case NFA_DEACTIVATED_EVT: // NFC link/protocol deactivated DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%s: NFA_DEACTIVATED_EVT Type: %u, gIsTagDeactivating: %d", __func__, eventData->deactivated.type, gIsTagDeactivating); NfcTag::getInstance().setDeactivationState(eventData->deactivated); if (eventData->deactivated.type != NFA_DEACTIVATE_TYPE_SLEEP) { { SyncEventGuard g(gDeactivatedEvent); gActivated = false; // guard this variable from multi-threaded access gDeactivatedEvent.notifyOne(); } nativeNfcTag_resetPresenceCheck(); NfcTag::getInstance().connectionEventHandler(connEvent, eventData); nativeNfcTag_abortWaits(); NfcTag::getInstance().abort(); } else if (gIsTagDeactivating) { NfcTag::getInstance().setActive(false); nativeNfcTag_doDeactivateStatus(0); } else if (EXTNS_GetDeactivateFlag() == TRUE) { NfcTag::getInstance().setActive(false); 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; } else if (sP2pActive) { sP2pActive = false; // Make sure RF field events are re-enabled DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: NFA_DEACTIVATED_EVT; is p2p", __func__); if (NFC_GetNCIVersion() == NCI_VERSION_1_0) { // Disable RF field events in case of p2p uint8_t nfa_enable_rf_events[] = {0x01}; if (!sIsDisabling && sIsNfaEnabled) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: Enabling RF field events", __func__); status = NFA_SetConfig(NCI_PARAM_ID_RF_FIELD_INFO, sizeof(nfa_enable_rf_events), &nfa_enable_rf_events[0]); if (status == NFA_STATUS_OK) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: Enabled RF field events", __func__); } else { LOG(ERROR) << StringPrintf( "%s: Failed to enable RF field events", __func__); } } } } } break; case NFA_TLV_DETECT_EVT: // TLV Detection complete status = eventData->tlv_detect.status; DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%s: NFA_TLV_DETECT_EVT: status = %d, protocol = %d, num_tlvs = %d, " "num_bytes = %d", __func__, status, eventData->tlv_detect.protocol, eventData->tlv_detect.num_tlvs, eventData->tlv_detect.num_bytes); if (status != NFA_STATUS_OK) { LOG(ERROR) << StringPrintf("%s: NFA_TLV_DETECT_EVT error: status = %d", __func__, 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; DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%s: NFA_NDEF_DETECT_EVT: status = 0x%X, protocol = %u, " "max_size = %u, cur_size = %u, flags = 0x%X", __func__, 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) DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: NFA_DATA_EVT: status = 0x%X, len = %d", __func__, eventData->status, eventData->data.len); nativeNfcTag_doTransceiveStatus(eventData->status, eventData->data.p_data, eventData->data.len); break; case NFA_RW_INTF_ERROR_EVT: DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: NFC_RW_INTF_ERROR_EVT", __func__); nativeNfcTag_notifyRfTimeout(); nativeNfcTag_doReadCompleted(NFA_STATUS_TIMEOUT); break; case NFA_SELECT_CPLT_EVT: // Select completed status = eventData->status; DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%s: NFA_SELECT_CPLT_EVT: status = %d", __func__, status); if (status != NFA_STATUS_OK) { LOG(ERROR) << StringPrintf("%s: NFA_SELECT_CPLT_EVT error: status = %d", __func__, status); } break; case NFA_READ_CPLT_EVT: // NDEF-read or tag-specific-read completed DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%s: NFA_READ_CPLT_EVT: status = 0x%X", __func__, eventData->status); nativeNfcTag_doReadCompleted(eventData->status); NfcTag::getInstance().connectionEventHandler(connEvent, eventData); break; case NFA_WRITE_CPLT_EVT: // Write completed DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%s: NFA_WRITE_CPLT_EVT: status = %d", __func__, eventData->status); nativeNfcTag_doWriteStatus(eventData->status == NFA_STATUS_OK); break; case NFA_SET_TAG_RO_EVT: // Tag set as Read only DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%s: NFA_SET_TAG_RO_EVT: status = %d", __func__, eventData->status); nativeNfcTag_doMakeReadonlyResult(eventData->status); break; case NFA_CE_NDEF_WRITE_START_EVT: // NDEF write started DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: NFA_CE_NDEF_WRITE_START_EVT: status: %d", __func__, eventData->status); if (eventData->status != NFA_STATUS_OK) LOG(ERROR) << StringPrintf( "%s: NFA_CE_NDEF_WRITE_START_EVT error: status = %d", __func__, eventData->status); break; case NFA_CE_NDEF_WRITE_CPLT_EVT: // NDEF write completed DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: FA_CE_NDEF_WRITE_CPLT_EVT: len = %u", __func__, eventData->ndef_write_cplt.len); break; case NFA_LLCP_ACTIVATED_EVT: // LLCP link is activated DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%s: NFA_LLCP_ACTIVATED_EVT: is_initiator: %d remote_wks: %d, " "remote_lsc: %d, remote_link_miu: %d, local_link_miu: %d", __func__, 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 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: NFA_LLCP_DEACTIVATED_EVT", __func__); PeerToPeer::getInstance().llcpDeactivatedHandler( getNative(0, 0), eventData->llcp_deactivated); break; case NFA_LLCP_FIRST_PACKET_RECEIVED_EVT: // Received first packet over llcp DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: NFA_LLCP_FIRST_PACKET_RECEIVED_EVT", __func__); PeerToPeer::getInstance().llcpFirstPacketHandler(getNative(0, 0)); break; case NFA_PRESENCE_CHECK_EVT: DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: NFA_PRESENCE_CHECK_EVT", __func__); nativeNfcTag_doPresenceCheckResult(eventData->status); break; case NFA_FORMAT_CPLT_EVT: DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%s: NFA_FORMAT_CPLT_EVT: status=0x%X", __func__, eventData->status); nativeNfcTag_formatStatus(eventData->status == NFA_STATUS_OK); break; case NFA_I93_CMD_CPLT_EVT: DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%s: NFA_I93_CMD_CPLT_EVT: status=0x%X", __func__, eventData->status); break; case NFA_CE_UICC_LISTEN_CONFIGURED_EVT: DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: NFA_CE_UICC_LISTEN_CONFIGURED_EVT : status=0x%X", __func__, eventData->status); break; case NFA_SET_P2P_LISTEN_TECH_EVT: DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: NFA_SET_P2P_LISTEN_TECH_EVT", __func__); PeerToPeer::getInstance().connectionEventHandler(connEvent, eventData); break; default: DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: unknown event ????", __func__); 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) { initializeGlobalDebugEnabledFlag(); DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: enter", __func__); nfc_jni_native_data* nat = (nfc_jni_native_data*)malloc(sizeof(struct nfc_jni_native_data)); if (nat == NULL) { LOG(ERROR) << StringPrintf("%s: fail allocate native data", __func__); return JNI_FALSE; } memset(nat, 0, sizeof(*nat)); e->GetJavaVM(&(nat->vm)); nat->env_version = e->GetVersion(); nat->manager = e->NewGlobalRef(o); ScopedLocalRef<jclass> cls(e, e->GetObjectClass(o)); jfieldID f = e->GetFieldID(cls.get(), "mNative", "J"); e->SetLongField(o, f, (jlong)nat); /* Initialize native cached references */ gCachedNfcManagerNotifyNdefMessageListeners = e->GetMethodID(cls.get(), "notifyNdefMessageListeners", "(Lcom/android/nfc/dhimpl/NativeNfcTag;)V"); gCachedNfcManagerNotifyLlcpLinkActivation = e->GetMethodID(cls.get(), "notifyLlcpLinkActivation", "(Lcom/android/nfc/dhimpl/NativeP2pDevice;)V"); gCachedNfcManagerNotifyLlcpLinkDeactivated = e->GetMethodID(cls.get(), "notifyLlcpLinkDeactivated", "(Lcom/android/nfc/dhimpl/NativeP2pDevice;)V"); gCachedNfcManagerNotifyLlcpFirstPacketReceived = e->GetMethodID(cls.get(), "notifyLlcpLinkFirstPacketReceived", "(Lcom/android/nfc/dhimpl/NativeP2pDevice;)V"); gCachedNfcManagerNotifyHostEmuActivated = e->GetMethodID(cls.get(), "notifyHostEmuActivated", "(I)V"); gCachedNfcManagerNotifyHostEmuData = e->GetMethodID(cls.get(), "notifyHostEmuData", "(I[B)V"); gCachedNfcManagerNotifyHostEmuDeactivated = e->GetMethodID(cls.get(), "notifyHostEmuDeactivated", "(I)V"); gCachedNfcManagerNotifyRfFieldActivated = e->GetMethodID(cls.get(), "notifyRfFieldActivated", "()V"); gCachedNfcManagerNotifyRfFieldDeactivated = e->GetMethodID(cls.get(), "notifyRfFieldDeactivated", "()V"); gCachedNfcManagerNotifyTransactionListeners = e->GetMethodID( cls.get(), "notifyTransactionListeners", "([B[BLjava/lang/String;)V"); if (nfc_jni_cache_object(e, gNativeNfcTagClassName, &(nat->cached_NfcTag)) == -1) { LOG(ERROR) << StringPrintf("%s: fail cache NativeNfcTag", __func__); return JNI_FALSE; } if (nfc_jni_cache_object(e, gNativeP2pDeviceClassName, &(nat->cached_P2pDevice)) == -1) { LOG(ERROR) << StringPrintf("%s: fail cache NativeP2pDevice", __func__); return JNI_FALSE; } DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: exit", __func__); 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_t dmEvent, tNFA_DM_CBACK_DATA* eventData) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: enter; event=0x%X", __func__, dmEvent); switch (dmEvent) { case NFA_DM_ENABLE_EVT: /* Result of NFA_Enable */ { SyncEventGuard guard(sNfaEnableEvent); DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%s: NFA_DM_ENABLE_EVT; status=0x%X", __func__, 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); DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: NFA_DM_DISABLE_EVT", __func__); sIsNfaEnabled = false; sIsDisabling = false; sNfaDisableEvent.notifyOne(); } break; case NFA_DM_SET_CONFIG_EVT: // result of NFA_SetConfig DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: NFA_DM_SET_CONFIG_EVT", __func__); { SyncEventGuard guard(sNfaSetConfigEvent); sNfaSetConfigEvent.notifyOne(); } break; case NFA_DM_GET_CONFIG_EVT: /* Result of NFA_GetConfig */ DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: NFA_DM_GET_CONFIG_EVT", __func__); { SyncEventGuard guard(sNfaGetConfigEvent); if (eventData->status == NFA_STATUS_OK && eventData->get_config.tlv_size <= sizeof(sConfig)) { sCurrentConfigLen = eventData->get_config.tlv_size; memcpy(sConfig, eventData->get_config.param_tlvs, eventData->get_config.tlv_size); } else { LOG(ERROR) << StringPrintf("%s: NFA_DM_GET_CONFIG failed", __func__); sCurrentConfigLen = 0; } sNfaGetConfigEvent.notifyOne(); } break; case NFA_DM_RF_FIELD_EVT: DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%s: NFA_DM_RF_FIELD_EVT; status=0x%X; field status=%u", __func__, eventData->rf_field.status, eventData->rf_field.rf_field_status); if (!sP2pActive && eventData->rf_field.status == NFA_STATUS_OK) { struct nfc_jni_native_data* nat = getNative(NULL, NULL); JNIEnv* e = NULL; ScopedAttach attach(nat->vm, &e); if (e == NULL) { LOG(ERROR) << StringPrintf("jni env is null"); return; } if (eventData->rf_field.rf_field_status == NFA_DM_RF_FIELD_ON) e->CallVoidMethod(nat->manager, android::gCachedNfcManagerNotifyRfFieldActivated); else e->CallVoidMethod(nat->manager, android::gCachedNfcManagerNotifyRfFieldDeactivated); } break; case NFA_DM_NFCC_TRANSPORT_ERR_EVT: case NFA_DM_NFCC_TIMEOUT_EVT: { if (dmEvent == NFA_DM_NFCC_TIMEOUT_EVT) LOG(ERROR) << StringPrintf("%s: NFA_DM_NFCC_TIMEOUT_EVT; abort", __func__); else if (dmEvent == NFA_DM_NFCC_TRANSPORT_ERR_EVT) LOG(ERROR) << StringPrintf("%s: NFA_DM_NFCC_TRANSPORT_ERR_EVT; abort", __func__); nativeNfcTag_abortWaits(); NfcTag::getInstance().abort(); sAbortConnlessWait = true; nativeLlcpConnectionlessSocket_abortWait(); { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%s: aborting sNfaEnableDisablePollingEvent", __func__); SyncEventGuard guard(sNfaEnableDisablePollingEvent); sNfaEnableDisablePollingEvent.notifyOne(); } { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: aborting sNfaEnableEvent", __func__); SyncEventGuard guard(sNfaEnableEvent); sNfaEnableEvent.notifyOne(); } { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: aborting sNfaDisableEvent", __func__); SyncEventGuard guard(sNfaDisableEvent); sNfaDisableEvent.notifyOne(); } sDiscoveryEnabled = false; sPollingEnabled = false; PowerSwitch::getInstance().abort(); if (!sIsDisabling && sIsNfaEnabled) { EXTNS_Close(); NFA_Disable(FALSE); sIsDisabling = true; } else { sIsNfaEnabled = false; sIsDisabling = false; } PowerSwitch::getInstance().initialize(PowerSwitch::UNKNOWN_LEVEL); LOG(ERROR) << StringPrintf("%s: crash NFC service", __func__); ////////////////////////////////////////////// // crash the NFC service process so it can restart automatically abort(); ////////////////////////////////////////////// } break; case NFA_DM_PWR_MODE_CHANGE_EVT: PowerSwitch::getInstance().deviceManagementCallback(dmEvent, eventData); break; case NFA_DM_SET_POWER_SUB_STATE_EVT: { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: NFA_DM_SET_POWER_SUB_STATE_EVT; status=0x%X", __FUNCTION__, eventData->power_sub_state.status); SyncEventGuard guard(sNfaSetPowerSubState); sNfaSetPowerSubState.notifyOne(); } break; default: DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: unhandled event", __func__); break; } } /******************************************************************************* ** ** Function: nfcManager_sendRawFrame ** ** Description: Send a raw frame. ** e: JVM environment. ** o: Java object. ** ** Returns: True if ok. ** *******************************************************************************/ static jboolean nfcManager_sendRawFrame(JNIEnv* e, jobject, jbyteArray data) { ScopedByteArrayRO bytes(e, data); uint8_t* buf = const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(&bytes[0])); size_t bufLen = bytes.size(); tNFA_STATUS status = NFA_SendRawFrame(buf, bufLen, 0); return (status == NFA_STATUS_OK); } /******************************************************************************* ** ** Function: nfcManager_routeAid ** ** Description: Route an AID to an EE ** e: JVM environment. ** aid: aid to be added to routing table. ** route: aid route location. i.e. DH/eSE/UICC ** aidInfo: prefix or suffix aid. ** ** Returns: True if aid is accpted by NFA Layer. ** *******************************************************************************/ static jboolean nfcManager_routeAid(JNIEnv* e, jobject, jbyteArray aid, jint route, jint aidInfo) { ScopedByteArrayRO bytes(e, aid); uint8_t* buf = const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(&bytes[0])); size_t bufLen = bytes.size(); return RoutingManager::getInstance().addAidRouting(buf, bufLen, route, aidInfo); } /******************************************************************************* ** ** Function: nfcManager_unrouteAid ** ** Description: Remove a AID routing ** e: JVM environment. ** o: Java object. ** ** Returns: True if ok. ** *******************************************************************************/ static jboolean nfcManager_unrouteAid(JNIEnv* e, jobject, jbyteArray aid) { ScopedByteArrayRO bytes(e, aid); uint8_t* buf = const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(&bytes[0])); size_t bufLen = bytes.size(); bool result = RoutingManager::getInstance().removeAidRouting(buf, bufLen); return result; } /******************************************************************************* ** ** Function: nfcManager_commitRouting ** ** Description: Sends the AID routing table to the controller ** e: JVM environment. ** o: Java object. ** ** Returns: True if ok. ** *******************************************************************************/ static jboolean nfcManager_commitRouting(JNIEnv* e, jobject) { if (sRfEnabled) { /*Update routing table only in Idle state.*/ startRfDiscovery(false); } jboolean commitStatus = RoutingManager::getInstance().commitRouting(); startRfDiscovery(true); return commitStatus; } /******************************************************************************* ** ** Function: nfcManager_doRegisterT3tIdentifier ** ** Description: Registers LF_T3T_IDENTIFIER for NFC-F. ** e: JVM environment. ** o: Java object. ** t3tIdentifier: LF_T3T_IDENTIFIER value (10 or 18 bytes) ** ** Returns: Handle retrieve from RoutingManager. ** *******************************************************************************/ static jint nfcManager_doRegisterT3tIdentifier(JNIEnv* e, jobject, jbyteArray t3tIdentifier) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: enter", __func__); ScopedByteArrayRO bytes(e, t3tIdentifier); uint8_t* buf = const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(&bytes[0])); size_t bufLen = bytes.size(); int handle = RoutingManager::getInstance().registerT3tIdentifier(buf, bufLen); DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: handle=%d", __func__, handle); if (handle != NFA_HANDLE_INVALID) RoutingManager::getInstance().commitRouting(); DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: exit", __func__); return handle; } /******************************************************************************* ** ** Function: nfcManager_doDeregisterT3tIdentifier ** ** Description: Deregisters LF_T3T_IDENTIFIER for NFC-F. ** e: JVM environment. ** o: Java object. ** handle: Handle retrieve from libnfc-nci. ** ** Returns: None ** *******************************************************************************/ static void nfcManager_doDeregisterT3tIdentifier(JNIEnv*, jobject, jint handle) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: enter; handle=%d", __func__, handle); RoutingManager::getInstance().deregisterT3tIdentifier(handle); RoutingManager::getInstance().commitRouting(); DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: exit", __func__); } /******************************************************************************* ** ** Function: nfcManager_getLfT3tMax ** ** Description: Returns LF_T3T_MAX value. ** e: JVM environment. ** o: Java object. ** ** Returns: LF_T3T_MAX value. ** *******************************************************************************/ static jint nfcManager_getLfT3tMax(JNIEnv*, jobject) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: enter", __func__); DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("LF_T3T_MAX=%d", sLfT3tMax); DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: exit", __func__); return sLfT3tMax; } /******************************************************************************* ** ** 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) { initializeGlobalDebugEnabledFlag(); tNFA_STATUS stat = NFA_STATUS_OK; PowerSwitch& powerSwitch = PowerSwitch::getInstance(); if (sIsNfaEnabled) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: already enabled", __func__); goto TheEnd; } powerSwitch.initialize(PowerSwitch::FULL_POWER); { 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) { sNfaEnableEvent.wait(); // wait for NFA command to finish } EXTNS_Init(nfaDeviceManagementCallback, nfaConnectionCallback); } if (stat == NFA_STATUS_OK) { // sIsNfaEnabled indicates whether stack started successfully if (sIsNfaEnabled) { RoutingManager::getInstance().initialize(getNative(e, o)); nativeNfcTag_registerNdefTypeHandler(); NfcTag::getInstance().initialize(getNative(e, o)); PeerToPeer::getInstance().initialize(); PeerToPeer::getInstance().handleNfcOnOff(true); HciEventManager::getInstance().initialize(getNative(e, o)); ///////////////////////////////////////////////////////////////////////////////// // Add extra configuration here (work-arounds, etc.) if (gIsDtaEnabled == true) { uint8_t configData = 0; configData = 0x01; /* Poll NFC-DEP : Highest Available Bit Rates */ NFA_SetConfig(NCI_PARAM_ID_BITR_NFC_DEP, sizeof(uint8_t), &configData); configData = 0x0B; /* Listen NFC-DEP : Waiting Time */ NFA_SetConfig(NFC_PMID_WT, sizeof(uint8_t), &configData); configData = 0x0F; /* Specific Parameters for NFC-DEP RF Interface */ NFA_SetConfig(NCI_PARAM_ID_NFC_DEP_OP, sizeof(uint8_t), &configData); } struct nfc_jni_native_data* nat = getNative(e, o); if (nat) { nat->tech_mask = NfcConfig::getUnsigned(NAME_POLLING_TECH_MASK, DEFAULT_TECH_MASK); DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%s: tag polling tech mask=0x%X", __func__, nat->tech_mask); } // if this value exists, set polling interval. nat->discovery_duration = NfcConfig::getUnsigned( NAME_NFA_DM_DISC_DURATION_POLL, DEFAULT_DISCOVERY_DURATION); NFA_SetRfDiscoveryDuration(nat->discovery_duration); // get LF_T3T_MAX { SyncEventGuard guard(sNfaGetConfigEvent); tNFA_PMID configParam[1] = {NCI_PARAM_ID_LF_T3T_MAX}; stat = NFA_GetConfig(1, configParam); if (stat == NFA_STATUS_OK) { sNfaGetConfigEvent.wait(); if (sCurrentConfigLen >= 4 || sConfig[1] == NCI_PARAM_ID_LF_T3T_MAX) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: lfT3tMax=%d", __func__, sConfig[3]); sLfT3tMax = sConfig[3]; } } } prevScreenState = NFA_SCREEN_STATE_OFF_LOCKED; // Do custom NFCA startup configuration. doStartupConfig(); goto TheEnd; } } LOG(ERROR) << StringPrintf("%s: fail nfa enable; error=0x%X", __func__, stat); if (sIsNfaEnabled) { EXTNS_Close(); stat = NFA_Disable(FALSE /* ungraceful */); } theInstance.Finalize(); } TheEnd: if (sIsNfaEnabled) PowerSwitch::getInstance().setLevel(PowerSwitch::LOW_POWER); DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: exit", __func__); return sIsNfaEnabled ? JNI_TRUE : JNI_FALSE; } static void nfcManager_doEnableDtaMode(JNIEnv*, jobject) { gIsDtaEnabled = true; } static void nfcManager_doDisableDtaMode(JNIEnv*, jobject) { gIsDtaEnabled = false; } static void nfcManager_doFactoryReset(JNIEnv*, jobject) { NfcAdaptation& theInstance = NfcAdaptation::GetInstance(); theInstance.FactoryReset(); } static void nfcManager_doShutdown(JNIEnv*, jobject) { NfcAdaptation& theInstance = NfcAdaptation::GetInstance(); theInstance.DeviceShutdown(); } /******************************************************************************* ** ** Function: nfcManager_enableDiscovery ** ** Description: Start polling and listening for devices. ** e: JVM environment. ** o: Java object. ** technologies_mask: the bitmask of technologies for which to *enable discovery ** enable_lptd: whether to enable low power polling (default: *false) ** ** Returns: None ** *******************************************************************************/ static void nfcManager_enableDiscovery(JNIEnv* e, jobject o, jint technologies_mask, jboolean enable_lptd, jboolean reader_mode, jboolean enable_host_routing, jboolean enable_p2p, jboolean restart) { tNFA_TECHNOLOGY_MASK tech_mask = DEFAULT_TECH_MASK; struct nfc_jni_native_data* nat = getNative(e, o); if (technologies_mask == -1 && nat) tech_mask = (tNFA_TECHNOLOGY_MASK)nat->tech_mask; else if (technologies_mask != -1) tech_mask = (tNFA_TECHNOLOGY_MASK)technologies_mask; DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: enter; tech_mask = %02x", __func__, tech_mask); if (sDiscoveryEnabled && !restart) { LOG(ERROR) << StringPrintf("%s: already discovering", __func__); return; } PowerSwitch::getInstance().setLevel(PowerSwitch::FULL_POWER); if (sRfEnabled) { // Stop RF discovery to reconfigure startRfDiscovery(false); } // Check polling configuration if (tech_mask != 0) { stopPolling_rfDiscoveryDisabled(); enableDisableLptd(enable_lptd); startPolling_rfDiscoveryDisabled(tech_mask); // Start P2P listening if tag polling was enabled if (sPollingEnabled) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: Enable p2pListening", __func__); if (enable_p2p && !sP2pEnabled) { sP2pEnabled = true; PeerToPeer::getInstance().enableP2pListening(true); NFA_ResumeP2p(); } else if (!enable_p2p && sP2pEnabled) { sP2pEnabled = false; PeerToPeer::getInstance().enableP2pListening(false); NFA_PauseP2p(); } if (reader_mode && !sReaderModeEnabled) { sReaderModeEnabled = true; NFA_DisableListening(); NFA_SetRfDiscoveryDuration(READER_MODE_DISCOVERY_DURATION); } else if (!reader_mode && sReaderModeEnabled) { struct nfc_jni_native_data* nat = getNative(e, o); sReaderModeEnabled = false; NFA_EnableListening(); NFA_SetRfDiscoveryDuration(nat->discovery_duration); } } } else { // No technologies configured, stop polling stopPolling_rfDiscoveryDisabled(); } // Check listen configuration if (enable_host_routing) { RoutingManager::getInstance().enableRoutingToHost(); RoutingManager::getInstance().commitRouting(); } else { RoutingManager::getInstance().disableRoutingToHost(); RoutingManager::getInstance().commitRouting(); } // Actually start discovery. startRfDiscovery(true); sDiscoveryEnabled = true; PowerSwitch::getInstance().setModeOn(PowerSwitch::DISCOVERY); DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: exit", __func__); } /******************************************************************************* ** ** 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; DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: enter;", __func__); pn544InteropAbortNow(); if (sDiscoveryEnabled == false) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: already disabled", __func__); goto TheEnd; } // Stop RF Discovery. startRfDiscovery(false); if (sPollingEnabled) status = stopPolling_rfDiscoveryDisabled(); PeerToPeer::getInstance().enableP2pListening(false); sP2pEnabled = false; sDiscoveryEnabled = 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: DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: exit", __func__); } void enableDisableLptd(bool enable) { // This method is *NOT* thread-safe. Right now // it is only called from the same thread so it's // not an issue. static bool sCheckedLptd = false; static bool sHasLptd = false; tNFA_STATUS stat = NFA_STATUS_OK; if (!sCheckedLptd) { sCheckedLptd = true; SyncEventGuard guard(sNfaGetConfigEvent); tNFA_PMID configParam[1] = {NCI_PARAM_ID_TAGSNIFF_CFG}; stat = NFA_GetConfig(1, configParam); if (stat != NFA_STATUS_OK) { LOG(ERROR) << StringPrintf("%s: NFA_GetConfig failed", __func__); return; } sNfaGetConfigEvent.wait(); if (sCurrentConfigLen < 4 || sConfig[1] != NCI_PARAM_ID_TAGSNIFF_CFG) { LOG(ERROR) << StringPrintf( "%s: Config TLV length %d returned is too short", __func__, sCurrentConfigLen); return; } if (sConfig[3] == 0) { LOG(ERROR) << StringPrintf( "%s: LPTD is disabled, not enabling in current config", __func__); return; } sHasLptd = true; } // Bail if we checked and didn't find any LPTD config before if (!sHasLptd) return; uint8_t enable_byte = enable ? 0x01 : 0x00; SyncEventGuard guard(sNfaSetConfigEvent); stat = NFA_SetConfig(NCI_PARAM_ID_TAGSNIFF_CFG, 1, &enable_byte); if (stat == NFA_STATUS_OK) sNfaSetConfigEvent.wait(); else LOG(ERROR) << StringPrintf("%s: Could not configure LPTD feature", __func__); return; } /******************************************************************************* ** ** 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, jint nSap, jstring sn, jint miu, jint rw, jint linearBufferLength) { PeerToPeer::tJNI_HANDLE jniHandle = PeerToPeer::getInstance().getNewJniHandle(); ScopedUtfChars serviceName(e, sn); DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%s: enter: sap=%i; name=%s; miu=%i; rw=%i; buffLen=%i", __func__, nSap, serviceName.c_str(), miu, rw, linearBufferLength); /* Create new NativeLlcpServiceSocket object */ jobject serviceSocket = NULL; if (nfc_jni_cache_object_local(e, gNativeLlcpServiceSocketClassName, &(serviceSocket)) == -1) { LOG(ERROR) << StringPrintf("%s: Llcp socket object creation error", __func__); return NULL; } /* Get NativeLlcpServiceSocket class object */ ScopedLocalRef<jclass> clsNativeLlcpServiceSocket( e, e->GetObjectClass(serviceSocket)); if (e->ExceptionCheck()) { e->ExceptionClear(); LOG(ERROR) << StringPrintf("%s: Llcp Socket get object class error", __func__); return NULL; } if (!PeerToPeer::getInstance().registerServer(jniHandle, serviceName.c_str())) { LOG(ERROR) << StringPrintf("%s: RegisterServer error", __func__); return NULL; } jfieldID f; /* Set socket handle to be the same as the NfaHandle*/ f = e->GetFieldID(clsNativeLlcpServiceSocket.get(), "mHandle", "I"); e->SetIntField(serviceSocket, f, (jint)jniHandle); DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: socket Handle = 0x%X", __func__, jniHandle); /* Set socket linear buffer length */ f = e->GetFieldID(clsNativeLlcpServiceSocket.get(), "mLocalLinearBufferLength", "I"); e->SetIntField(serviceSocket, f, (jint)linearBufferLength); DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: buffer length = %d", __func__, linearBufferLength); /* Set socket MIU */ f = e->GetFieldID(clsNativeLlcpServiceSocket.get(), "mLocalMiu", "I"); e->SetIntField(serviceSocket, f, (jint)miu); DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: MIU = %d", __func__, miu); /* Set socket RW */ f = e->GetFieldID(clsNativeLlcpServiceSocket.get(), "mLocalRw", "I"); e->SetIntField(serviceSocket, f, (jint)rw); DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: RW = %d", __func__, rw); sLastError = 0; DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: exit", __func__); 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*, jobject) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: last error=%i", __func__, 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*, jobject) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: enter", __func__); sIsDisabling = true; pn544InteropAbortNow(); RoutingManager::getInstance().onNfccShutdown(); PowerSwitch::getInstance().initialize(PowerSwitch::UNKNOWN_LEVEL); HciEventManager::getInstance().finalize(); if (sIsNfaEnabled) { SyncEventGuard guard(sNfaDisableEvent); EXTNS_Close(); tNFA_STATUS stat = NFA_Disable(TRUE /* graceful */); if (stat == NFA_STATUS_OK) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: wait for completion", __func__); sNfaDisableEvent.wait(); // wait for NFA command to finish PeerToPeer::getInstance().handleNfcOnOff(false); } else { LOG(ERROR) << StringPrintf("%s: fail disable; error=0x%X", __func__, stat); } } nativeNfcTag_abortWaits(); NfcTag::getInstance().abort(); sAbortConnlessWait = true; nativeLlcpConnectionlessSocket_abortWait(); sIsNfaEnabled = false; sDiscoveryEnabled = false; sPollingEnabled = false; sIsDisabling = false; sP2pEnabled = false; gActivated = false; sLfT3tMax = 0; { // unblock NFA_EnablePolling() and NFA_DisablePolling() SyncEventGuard guard(sNfaEnableDisablePollingEvent); sNfaEnableDisablePollingEvent.notifyOne(); } NfcAdaptation& theInstance = NfcAdaptation::GetInstance(); theInstance.Finalize(); DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: exit", __func__); 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, jint nSap, jint miu, jint rw, jint linearBufferLength) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: enter; sap=%d; miu=%d; rw=%d; buffer len=%d", __func__, nSap, miu, rw, linearBufferLength); PeerToPeer::tJNI_HANDLE jniHandle = PeerToPeer::getInstance().getNewJniHandle(); PeerToPeer::getInstance().createClient(jniHandle, miu, rw); /* Create new NativeLlcpSocket object */ jobject clientSocket = NULL; if (nfc_jni_cache_object_local(e, gNativeLlcpSocketClassName, &(clientSocket)) == -1) { LOG(ERROR) << StringPrintf("%s: fail Llcp socket creation", __func__); return clientSocket; } /* Get NativeConnectionless class object */ ScopedLocalRef<jclass> clsNativeLlcpSocket(e, e->GetObjectClass(clientSocket)); if (e->ExceptionCheck()) { e->ExceptionClear(); LOG(ERROR) << StringPrintf("%s: fail get class object", __func__); return clientSocket; } jfieldID f; /* Set socket SAP */ f = e->GetFieldID(clsNativeLlcpSocket.get(), "mSap", "I"); e->SetIntField(clientSocket, f, (jint)nSap); /* Set socket handle */ f = e->GetFieldID(clsNativeLlcpSocket.get(), "mHandle", "I"); e->SetIntField(clientSocket, f, (jint)jniHandle); /* Set socket MIU */ f = e->GetFieldID(clsNativeLlcpSocket.get(), "mLocalMiu", "I"); e->SetIntField(clientSocket, f, (jint)miu); /* Set socket RW */ f = e->GetFieldID(clsNativeLlcpSocket.get(), "mLocalRw", "I"); e->SetIntField(clientSocket, f, (jint)rw); DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: exit", __func__); 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*, jobject, jint nSap, jstring /*sn*/) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: nSap=0x%X", __func__, nSap); return NULL; } /******************************************************************************* ** ** 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*, jobject) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", __func__); return JNI_TRUE; } /******************************************************************************* ** ** Function: nfcManager_doActivateLlcp ** ** Description: Not used. ** ** Returns: True ** *******************************************************************************/ static jboolean nfcManager_doActivateLlcp(JNIEnv*, jobject) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", __func__); return JNI_TRUE; } /******************************************************************************* ** ** Function: nfcManager_doAbort ** ** Description: Not used. ** ** Returns: None ** *******************************************************************************/ static void nfcManager_doAbort(JNIEnv* e, jobject, jstring msg) { ScopedUtfChars message = {e, msg}; e->FatalError(message.c_str()); abort(); // <-- Unreachable } /******************************************************************************* ** ** Function: nfcManager_doDownload ** ** Description: Download firmware patch files. Do not turn on NFC. ** ** Returns: True if ok. ** *******************************************************************************/ static jboolean nfcManager_doDownload(JNIEnv*, jobject) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: enter", __func__); NfcAdaptation& theInstance = NfcAdaptation::GetInstance(); theInstance.Initialize(); // start GKI, NCI task, NFC task theInstance.DownloadFirmware(); theInstance.Finalize(); DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: exit", __func__); return JNI_TRUE; } /******************************************************************************* ** ** Function: nfcManager_doResetTimeouts ** ** Description: Not used. ** ** Returns: None ** *******************************************************************************/ static void nfcManager_doResetTimeouts(JNIEnv*, jobject) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", __func__); NfcTag::getInstance().resetAllTransceiveTimeouts(); } /******************************************************************************* ** ** Function: nfcManager_doSetTimeout ** ** Description: Set timeout value. ** e: JVM environment. ** o: Java object. ** tech: technology ID. ** timeout: Timeout value. ** ** Returns: True if ok. ** *******************************************************************************/ static bool nfcManager_doSetTimeout(JNIEnv*, jobject, jint tech, jint timeout) { if (timeout <= 0) { LOG(ERROR) << StringPrintf("%s: Timeout must be positive.", __func__); return false; } DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: tech=%d, timeout=%d", __func__, tech, timeout); NfcTag::getInstance().setTransceiveTimeout(tech, timeout); return true; } /******************************************************************************* ** ** Function: nfcManager_doGetTimeout ** ** Description: Get timeout value. ** e: JVM environment. ** o: Java object. ** tech: technology ID. ** ** Returns: Timeout value. ** *******************************************************************************/ static jint nfcManager_doGetTimeout(JNIEnv*, jobject, jint tech) { int timeout = NfcTag::getInstance().getTransceiveTimeout(tech); DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: tech=%d, timeout=%d", __func__, tech, timeout); return timeout; } /******************************************************************************* ** ** Function: nfcManager_doDump ** ** Description: Get libnfc-nci dump ** e: JVM environment. ** obj: Java object. ** fdobj: File descriptor to be used ** ** Returns: Void ** *******************************************************************************/ static void nfcManager_doDump(JNIEnv* e, jobject obj, jobject fdobj) { int fd = jniGetFDFromFileDescriptor(e, fdobj); if (fd < 0) return; NfcAdaptation& theInstance = NfcAdaptation::GetInstance(); theInstance.Dump(fd); } static jint nfcManager_doGetNciVersion(JNIEnv*, jobject) { return NFC_GetNCIVersion(); } static void nfcManager_doSetScreenState(JNIEnv* e, jobject o, jint screen_state_mask) { tNFA_STATUS status = NFA_STATUS_OK; uint8_t state = (screen_state_mask & NFA_SCREEN_STATE_MASK); uint8_t discovry_param = NCI_LISTEN_DH_NFCEE_ENABLE_MASK | NCI_POLLING_DH_ENABLE_MASK; DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: state = %d prevScreenState= %d, discovry_param = %d", __FUNCTION__, state, prevScreenState, discovry_param); if (sIsDisabling || !sIsNfaEnabled || (NFC_GetNCIVersion() != NCI_VERSION_2_0)) return; if (prevScreenState == NFA_SCREEN_STATE_OFF_LOCKED || prevScreenState == NFA_SCREEN_STATE_OFF_UNLOCKED || prevScreenState == NFA_SCREEN_STATE_ON_LOCKED) { SyncEventGuard guard(sNfaSetPowerSubState); status = NFA_SetPowerSubStateForScreenState(state); if (status != NFA_STATUS_OK) { LOG(ERROR) << StringPrintf("%s: fail enable SetScreenState; error=0x%X", __FUNCTION__, status); return; } else { sNfaSetPowerSubState.wait(); } } if (state == NFA_SCREEN_STATE_OFF_LOCKED || state == NFA_SCREEN_STATE_OFF_UNLOCKED) { // disable both poll and listen on DH 0x02 discovry_param = NCI_POLLING_DH_DISABLE_MASK | NCI_LISTEN_DH_NFCEE_DISABLE_MASK; } if (state == NFA_SCREEN_STATE_ON_LOCKED) { // disable poll and enable listen on DH 0x00 discovry_param = (screen_state_mask & NFA_SCREEN_POLLING_TAG_MASK) ? (NCI_LISTEN_DH_NFCEE_ENABLE_MASK | NCI_POLLING_DH_ENABLE_MASK) : (NCI_POLLING_DH_DISABLE_MASK | NCI_LISTEN_DH_NFCEE_ENABLE_MASK); } if (state == NFA_SCREEN_STATE_ON_UNLOCKED) { // enable both poll and listen on DH 0x01 discovry_param = NCI_LISTEN_DH_NFCEE_ENABLE_MASK | NCI_POLLING_DH_ENABLE_MASK; } SyncEventGuard guard(sNfaSetConfigEvent); status = NFA_SetConfig(NCI_PARAM_ID_CON_DISCOVERY_PARAM, NCI_PARAM_LEN_CON_DISCOVERY_PARAM, &discovry_param); if (status == NFA_STATUS_OK) { sNfaSetConfigEvent.wait(); } else { LOG(ERROR) << StringPrintf("%s: Failed to update CON_DISCOVER_PARAM", __FUNCTION__); return; } if (prevScreenState == NFA_SCREEN_STATE_ON_UNLOCKED) { SyncEventGuard guard(sNfaSetPowerSubState); status = NFA_SetPowerSubStateForScreenState(state); if (status != NFA_STATUS_OK) { LOG(ERROR) << StringPrintf("%s: fail enable SetScreenState; error=0x%X", __FUNCTION__, status); } else { sNfaSetPowerSubState.wait(); } } if ((state == NFA_SCREEN_STATE_OFF_LOCKED || state == NFA_SCREEN_STATE_OFF_UNLOCKED) && prevScreenState == NFA_SCREEN_STATE_ON_UNLOCKED) { // screen turns off, disconnect tag if connected nativeNfcTag_doDisconnect(NULL, NULL); } prevScreenState = state; } /******************************************************************************* ** ** 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) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: modes=0x%X", __func__, 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; } /******************************************************************************* ** ** 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*, jobject, jint modes) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: modes=0x%X", __func__, 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); } static void nfcManager_doEnableScreenOffSuspend(JNIEnv* e, jobject o) { PowerSwitch::getInstance().setScreenOffPowerState( PowerSwitch::POWER_STATE_FULL); } static void nfcManager_doDisableScreenOffSuspend(JNIEnv* e, jobject o) { PowerSwitch::getInstance().setScreenOffPowerState( PowerSwitch::POWER_STATE_OFF); } /******************************************************************************* ** ** Function: nfcManager_getIsoDepMaxTransceiveLength ** ** Description: Get maximum ISO DEP Transceive Length supported by the NFC ** chip. Returns default 261 bytes if the property is not set. ** ** Returns: max value. ** *******************************************************************************/ static jint nfcManager_getIsoDepMaxTransceiveLength(JNIEnv*, jobject) { /* Check if extended APDU is supported by the chip. * If not, default value is returned. * The maximum length of a default IsoDep frame consists of: * CLA, INS, P1, P2, LC, LE + 255 payload bytes = 261 bytes */ return NfcConfig::getUnsigned(NAME_ISO_DEP_MAX_TRANSCEIVE, 261); } /***************************************************************************** ** ** 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}, {"sendRawFrame", "([B)Z", (void*)nfcManager_sendRawFrame}, {"routeAid", "([BII)Z", (void*)nfcManager_routeAid}, {"unrouteAid", "([B)Z", (void*)nfcManager_unrouteAid}, {"commitRouting", "()Z", (void*)nfcManager_commitRouting}, {"doRegisterT3tIdentifier", "([B)I", (void*)nfcManager_doRegisterT3tIdentifier}, {"doDeregisterT3tIdentifier", "(I)V", (void*)nfcManager_doDeregisterT3tIdentifier}, {"getLfT3tMax", "()I", (void*)nfcManager_getLfT3tMax}, {"doEnableDiscovery", "(IZZZZZ)V", (void*)nfcManager_enableDiscovery}, {"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", "(Ljava/lang/String;)V", (void*)nfcManager_doAbort}, {"doSetP2pInitiatorModes", "(I)V", (void*)nfcManager_doSetP2pInitiatorModes}, {"doSetP2pTargetModes", "(I)V", (void*)nfcManager_doSetP2pTargetModes}, {"doEnableScreenOffSuspend", "()V", (void*)nfcManager_doEnableScreenOffSuspend}, {"doSetScreenState", "(I)V", (void*)nfcManager_doSetScreenState}, {"doDisableScreenOffSuspend", "()V", (void*)nfcManager_doDisableScreenOffSuspend}, {"doDump", "(Ljava/io/FileDescriptor;)V", (void*)nfcManager_doDump}, {"getNciVersion", "()I", (void*)nfcManager_doGetNciVersion}, {"doEnableDtaMode", "()V", (void*)nfcManager_doEnableDtaMode}, {"doDisableDtaMode", "()V", (void*)nfcManager_doDisableDtaMode}, {"doFactoryReset", "()V", (void*)nfcManager_doFactoryReset}, {"doShutdown", "()V", (void*)nfcManager_doShutdown}, {"getIsoDepMaxTransceiveLength", "()I", (void*)nfcManager_getIsoDepMaxTransceiveLength} }; /******************************************************************************* ** ** 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) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: enter", __func__); PowerSwitch::getInstance().initialize(PowerSwitch::UNKNOWN_LEVEL); DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: exit", __func__); 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; DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: is start=%d", __func__, isStart); nativeNfcTag_acquireRfInterfaceMutexLock(); 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 { LOG(ERROR) << StringPrintf( "%s: Failed to start/stop RF discovery; error=0x%X", __func__, status); } nativeNfcTag_releaseRfInterfaceMutexLock(); } /******************************************************************************* ** ** Function: isDiscoveryStarted ** ** Description: Indicates whether the discovery is started. ** ** Returns: True if discovery is started ** *******************************************************************************/ bool isDiscoveryStarted() { return sRfEnabled; } /******************************************************************************* ** ** Function: doStartupConfig ** ** Description: Configure the NFC controller. ** ** Returns: None ** *******************************************************************************/ void doStartupConfig() { struct nfc_jni_native_data* nat = getNative(0, 0); tNFA_STATUS stat = NFA_STATUS_FAILED; // 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_t 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(); } // configure RF polling frequency for each technology static tNFA_DM_DISC_FREQ_CFG nfa_dm_disc_freq_cfg; // values in the polling_frequency[] map to members of nfa_dm_disc_freq_cfg std::vector<uint8_t> polling_frequency; if (NfcConfig::hasKey(NAME_POLL_FREQUENCY)) polling_frequency = NfcConfig::getBytes(NAME_POLL_FREQUENCY); if (polling_frequency.size() == 8) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: polling frequency", __func__); memset(&nfa_dm_disc_freq_cfg, 0, sizeof(nfa_dm_disc_freq_cfg)); nfa_dm_disc_freq_cfg.pa = polling_frequency[0]; nfa_dm_disc_freq_cfg.pb = polling_frequency[1]; nfa_dm_disc_freq_cfg.pf = polling_frequency[2]; nfa_dm_disc_freq_cfg.pi93 = polling_frequency[3]; nfa_dm_disc_freq_cfg.pbp = polling_frequency[4]; nfa_dm_disc_freq_cfg.pk = polling_frequency[5]; nfa_dm_disc_freq_cfg.paa = polling_frequency[6]; nfa_dm_disc_freq_cfg.pfa = polling_frequency[7]; p_nfa_dm_rf_disc_freq_cfg = &nfa_dm_disc_freq_cfg; } } /******************************************************************************* ** ** 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) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: enter; isStart=%u", __func__, isStartPolling); startRfDiscovery(false); if (isStartPolling) startPolling_rfDiscoveryDisabled(0); else stopPolling_rfDiscoveryDisabled(); startRfDiscovery(true); DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: exit", __func__); } static tNFA_STATUS startPolling_rfDiscoveryDisabled( tNFA_TECHNOLOGY_MASK tech_mask) { tNFA_STATUS stat = NFA_STATUS_FAILED; if (tech_mask == 0) tech_mask = NfcConfig::getUnsigned(NAME_POLLING_TECH_MASK, DEFAULT_TECH_MASK); nativeNfcTag_acquireRfInterfaceMutexLock(); SyncEventGuard guard(sNfaEnableDisablePollingEvent); DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: enable polling", __func__); stat = NFA_EnablePolling(tech_mask); if (stat == NFA_STATUS_OK) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: wait for enable event", __func__); sPollingEnabled = true; sNfaEnableDisablePollingEvent.wait(); // wait for NFA_POLL_ENABLED_EVT } else { LOG(ERROR) << StringPrintf("%s: fail enable polling; error=0x%X", __func__, stat); } nativeNfcTag_releaseRfInterfaceMutexLock(); return stat; } static tNFA_STATUS stopPolling_rfDiscoveryDisabled() { tNFA_STATUS stat = NFA_STATUS_FAILED; nativeNfcTag_acquireRfInterfaceMutexLock(); SyncEventGuard guard(sNfaEnableDisablePollingEvent); DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: disable polling", __func__); stat = NFA_DisablePolling(); if (stat == NFA_STATUS_OK) { sPollingEnabled = false; sNfaEnableDisablePollingEvent.wait(); // wait for NFA_POLL_DISABLED_EVT } else { LOG(ERROR) << StringPrintf("%s: fail disable polling; error=0x%X", __func__, stat); } nativeNfcTag_releaseRfInterfaceMutexLock(); return stat; } } /* namespace android */