NFC功能介绍java
NFC 目前使用的三种功能:android
1. P2P模式:基于LLCP协议的基础上,以NDEF数据交换格式来通讯。git
2. 读写模式:看成为读卡器,对NFC Tag的读写。web
3. 卡模拟模式:模块成卡,能够与读卡器(或pos机)进行数据通讯。安全
kernel-3.10/drivers/misc/mediatek/nfc/nxpapp
1. 增长 packages/apps/Nfc-nxpsocket
2. 增长 vendor/NXP/device函数
3. 更改 hardware/libhardware/include/hardware/nfc.h 动画
4. 增长 frameworks/base/gsma-extras/java/com/android/nfcgsma_extras/NfcAdapterGsmaExtras.javaspa
5. 增长 frameworks/base/core/java/com/vzw
6. 增长 frameworks/base/core/java/com/nxp
7. 更改替换 frameworks/base/core/java/android/nfc
8. 更改替换 frameworks/base/Android.mk
9. 增长 external/libp61-jcop-kit
10.增长 external/libnfc-nci-nxp
11.增长 external/dta
12. 更改 device/mediatek/common/device.mk (增长对 vendor/NXP/device/device-NXP.mk 的编译选项)
1 <application android:name=".NfcApplication" 2 android:icon="@drawable/icon" 3 android:label="@string/app_name" 4 android:theme="@android:style/Theme.Material.Light" 5 android:persistent="true"
NfcApplication 会在Android SystemReady 时启动,从而会把NfcService 这个服务启动起来。
public NfcService(Application nfcApplication) { mUserId = ActivityManager.getCurrentUser(); mContext = nfcApplication; mNfcTagService = new TagService(); mNfcAdapter = new NfcAdapterService(); mNxpNfcAdapter = new NxpNfcAdapterService(); mExtrasService = new NfcAdapterExtrasService(); mNxpExtrasService = new NxpNfcAdapterExtrasService();
TagService 是对Tag的读写服务
NfcAdapterService 是 NfcAdapter 的远端服务。对NFC功能的操做的服务(包括打开,关闭,设置工做模式等)。
NxpNfcAdapterService 是NXP Ic 控制和设置的服务。有 获取控制的接口,选择路由,设置配置参数,还有对ese的访问等。
NfcAdapterExtraService 是卡模拟功能的服务。打开关闭卡模拟,获取,设置卡模拟路由。
NxpNfcAdapterExtrasService 是 ese 安全功能的服务。获取,指定安全访问路由。
NfcService初始化的时序图:
1 NfcAdaptation& theInstance = NfcAdaptation::GetInstance(); 2 theInstance.Initialize(); //start GKI, NCI task, NFC task 3 建立NCI task 线程和 NFC task 线程 4 5 NFA_Init (halFuncEntries); 6 stat = NFA_Enable (nfaDeviceManagementCallback, nfaConnectionCallback); 7 8 SecureElement::getInstance().initialize (getNative(e, o)); 9 //setListenMode(); 10 RoutingManager::getInstance().initialize(getNative(e, o)); 11 HciRFParams::getInstance().initialize (); 12 sIsSecElemSelected = (SecureElement::getInstance().getActualNumEe() - 1 ); 13 sIsSecElemDetected = sIsSecElemSelected; 14 nativeNfcTag_registerNdefTypeHandler (); 15 NfcTag::getInstance().initialize (getNative(e, o)); 16 PeerToPeer::getInstance().initialize (); 17 PeerToPeer::getInstance().handleNfcOnOff (true);
这里面基本都是NXP 硬件 和 HAL层的初始化。重点看看 NfcAdaptation Initialize()
1 void NfcAdaptation::Initialize () 2 { 3 .......................................................... 4 InitializeHalDeviceContext (); 5 ......................................................... 6 }
继续看 InitializeHalDeviceContext()
1 void NfcAdaptation::InitializeHalDeviceContext (){ 2 …......................................................... 3 ret = hw_get_module (nci_hal_module, &hw_module); 4 if (ret == 0) 5 { 6 ret = nfc_nci_open (hw_module, &mHalDeviceContext); 7 if (ret != 0) 8 ALOGE ("%s: nfc_nci_open fail", func); 9 } 10 }
这一块就对NFC HAL 作了初始化了,咱们再继续往下跟会发现建立了两个线程,一个读线程,一个写线程:
1 /* Create Reader and Writer threads */ 2 pthread_create_status = pthread_create(&gpphTmlNfc_Context->readerThread,NULL,(void *)&phTmlNfc_TmlThread, 3 (void *)h_threadsEvent); 4 if(0 != pthread_create_status) 5 { 6 wStartStatus = NFCSTATUS_FAILED; 7 } 8 else 9 { 10 /*Start Writer Thread*/ 11 pthread_create_status = pthread_create(&gpphTmlNfc_Context->writerThread,NULL,(void *)&phTmlNfc_TmlWriterThread, (void *)h_threadsEvent); 12 if(0 != pthread_create_status) 13 { 14 wStartStatus = NFCSTATUS_FAILED; 15 } 16 }
读线程调用select 对 设备节点/dev/pn544作了监听挂起, 有nfc 检测到有设备 中断上来时,会将数据写往此设备节点,此时监听线程 检测到有数据写入时,会唤醒线程来读出写入的数据。
1 ret_Select = select((int)((intptr_t)pDevHandle + (int)1), &rfds, NULL, NULL, &tv); 2 if (ret_Select < 0) 3 { 4 NXPLOG_TML_E("i2c select() errno : %x",errno); 5 return -1; 6 } 7 else if (ret_Select == 0) 8 { 9 NXPLOG_TML_E("i2c select() Timeout"); 10 return -1; 11 } 12 else 13 { 14 ret_Read = read((intptr_t)pDevHandle, pBuffer, totalBtyesToRead – numRead);
当有TAG靠近手机NFC读写区域,驱动中会触发中断,把读到数据写入到设备节点中,i2c读线程会唤醒,读到数据后,将数据封装好,回调指定的回调函数,将数据和消息类型封装成一个消息,而后发送消息任务线程去处理,再回调指定的监听。
从jni中 NativeNfcManager.cpp 中 经过NotifyNdefMessageListeners回调到 NativeNfcManager.java中,再经过OnRemoteEndPointDiscovered回传到NfcService中. NfcSevice 再作Dispatch分发,将NDEF 消息格式解析中,再根据类型,找到最合适的Activity 来启动。
看看 NDEF 的格式:
Bundle extras = tag.getTechExtras(TagTechnology.NDEF);
if (extras != null) {
mMaxNdefSize = extras.getInt(EXTRA_NDEF_MAXLENGTH);
mCardState = extras.getInt(EXTRA_NDEF_CARDSTATE);
mNdefMsg = extras.getParcelable(EXTRA_NDEF_MSG);
mNdefType = extras.getInt(EXTRA_NDEF_TYPE);
}
看看时序图:
当两上机器靠近时,中断来了,驱动就会往/dev/pn544设备中写数据,从而唤醒i2c_reader 线程,从而根据报来的消息类型,会调用NativeNfcManager 去处理此类型消息,而后notifyLlcpLinkActivation, 告诉NativeNfcManager有P2P的消息来了,而且回调NfcService的onLlcpLinkActivated。NfcService 会把此消息交给NfcServiceHandler来处理,此时会调用P2PLinkManager的onLlcpActivated。而后 会调用P2pEventManager的onP2pSendConfirmationRequested来确认是否p2pSend。 这个P2PEventManager 会调用SendUi 里的 showPreSend. 这个sendUi就在界面上作UI处理了(这个是一个传界面的UI,还有一个fileSendUi 专用于传文件的UI显示,根据当前界面为判断用哪一种UI来显示),就是咱们看到缩小的界面图了。这个showPreSend 其实作了一个截屏的操做,而后加上了一个动画,让其缩小,并提示“触摸便可传输”。当咱们点击屏幕,就是调用onTouch事件了, sendUi 显示一个动画,而后就是sendNdefMessage。
咱们再来看看 sendNdefMessage的过程:
最后就是经过 SnepClient 经过SnepMessager 将消息发送出来。SnepClient 其实就是在sendNdefMessage之间就有个connect的操做, 这个connect就是建立了一个socket 去链接服务端的socket。sendMessage 就是经过socket 把这个给消息给发过去。
固然根据传的东西不一样,若是传的文件,歌曲,图片,咱们会启动 wifiDirect去传输。Android原生会调用蓝牙来传输。
咱们先看一下接收一个时序图:
P2P的接收就简单说明下,NfcService 启动的时候,会实例化P2PLinkManager, 同时 P2PLinkManager会实例化一个SnepServer (这时候应该想到send过程当中的SnepClient),会开启两个进程,一个是Socket进程,就是会监听接收客户端的sockek链接。 另外一个就是ConnectionThread,用于将链接到messager 处理,会回调 P2PLinkManager 的doGet 和 doPut.. 这时就成功能将Ndef的消息获取到了。以后的流程就与TAG的读过程差很少了,解析Message, 而后dispatcher, 启动对应的Activity.