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.