這篇文章用來分析NFC學習——NFC Enable 過程分析(一) 中setp 3-2:開啓一些循環監聽的線程服務。處理方法enableDisable().
code路徑:packages/apps/nfc/src/com/android/nfc/P2pLinkManager.java,具體看enableDisable()中的處理code:
public void enableDisable(boolean sendEnable, boolean receiveEnable) {
synchronized (this) {
if (!mIsReceiveEnabled && receiveEnable) {
//setp1:啓動SnepServer
mDefaultSnepServer.start();
//setp2:啓動NdefPushServer
mNdefPushServer.start();
if (mEchoServer != null) {
//setp3:啓動EchoServer
mHandler.sendEmptyMessage(MSG_START_ECHOSERVER);
}
}
}
}
Setp1:啓動SnepServer,此Server的作用是接收NDEF消息,並把它推送給LLCP(Logical Link Control Protocol).啓動SnepServer最後轉到其內部類ServerThread去處理,ServerThread繼承Thread,具體分析它的run方法。
code路徑:packages/apps/nfc/src/com/android/nfc/snep/SnepServer.java
public void run() {
........
while (threadRunning) {
synchronized (SnepServer.this) {
//setp1-1:創建一個服務器端Socket連接
mServerSocket = NfcService.getInstance().createLlcpServerSocket(mServiceSap,
mServiceName, MIU, 1, 1024);
}
......
//接收Socket請求
LlcpSocket communicationSocket = serverSocket.accept();
if (communicationSocket != null) {
//setp1-2:miu 是什麼,如何獲取來的
int miu = communicationSocket.getRemoteMiu();
int fragmentLength = (mFragmentLength == -1) ?
miu : Math.min(miu, mFragmentLength);
//setp1-3: 啓動線程處理SnepMessenger
new ConnectionThread(communicationSocket, fragmentLength).start();
}
......
}
}
Setp1-1:創建服務器端mServerSocket中參數如下:
mServiceSap:socket 端口,默認是4;
mServiceName:從命名可以看出,它是socket名稱
MIU:全稱是Maximum information Unit ,LLCP中數據單元中消息最大的長度(不知道是不是按byte算的),
1:
1024:是buffer的長度,至於它的作用是什麼,贊時還不知道。
mServerSocket的創建過程:通過NfcService調用createLlcpServerSocket(),而NfcService直接返回的DeviceHost.createLlcpServerSocket()的調用,DeviceHost僅僅只是一個接口,DeviceHost.createLlcpServerSocket()具體實現在NativeNfcManager.createLlcpServerSocket().NativeNfcManager則直接調用JNI方法com_android_nfc_NfcManager_doCreateLlcpServiceSocket()來實現其創建功能,其中的參數爲了書寫方便都省略了。
static jobject com_android_nfc_NfcManager_doCreateLlcpServiceSocket(JNIEnv *e, jobject o,
jint nSap, jstring sn, jint miu, jint rw, jint linearBufferLength)
{
......
/* Create socket */
/*setp1-1-1:函數在external/libnfc-nxp/src/phLibNfc.h聲明,具體的函數作用,函數參數含義請查看代碼中註釋,&hLlcpSocket即是創建成功的Sokect的指針*/
ret = phLibNfc_Llcp_Socket(phFriNfc_LlcpTransport_eConnectionOriented,
&sOptions,
&sWorkingBuffer,
&hLlcpSocket,
nfc_jni_llcp_transport_socket_err_callback,
(void*)nat);
......
/* Create new NativeLlcpServiceSocket object,到此出現了我們分析到目前的 mServerSocket的創建,返回的serviceSocket就是*/
if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpServiceSocket",&(serviceSocket)) == -1)
{
ALOGE("Llcp Socket object creation error");
goto error;
}
......
return serviceSocket;
}
附上一張思路圖,就清晰點
Setp1-2:miu如何得來的,看下面分析圖
看到這張圖,可能只是對函數的調用過程有個清晰的瞭解,但是miu到底是如何獲取到的呢??這次我們從函數的調用最後來分析,即phFriNfc_LlcpTransport_Connection.c這個文件的函數。
NFCSTATUS phFriNfc_LlcpTransport_ConnectionOriented_SocketGetRemoteOptions(
phFriNfc_LlcpTransport_Socket_t* pLlcpSocket,
phLibNfc_Llcp_sSocketOptions_t* psRemoteOptions)
{
NFCSTATUS status = NFCSTATUS_SUCCESS;
/* Get Remote MIUX */
psRemoteOptions->miu = pLlcpSocket->remoteMIU;
/* Get Remote Receive Window */
psRemoteOptions->rw = pLlcpSocket->remoteRW;
return status;
}
上面code可以發現phFriNfc_LlcpTransport_Socket_t 的remoteMIU 直接賦給phLibNfc_Llcp_sSocketOptions_t的miu.這就是我們要找的答案。phFriNfc_LlcpTransport_Socket_t 和phLibNfc_Llcp_sSocketOptions_t具體是什麼就不做研究了。setp1-3: 啓動線程處理SnepMessenger,從新開啓一個Thread處理SnepMessage,處理code 還是SnepServer.java
static boolean handleRequest(SnepMessenger messenger, Callback callback) throws IOException {
SnepMessage request;
......
//從SnepMessenger中取出SnepMessage
request = messenger.getMessage();
if (((request.getVersion() & 0xF0) >> 4) != SnepMessage.VERSION_MAJOR) {
messenger.sendMessage(SnepMessage.getMessage(
SnepMessage.RESPONSE_UNSUPPORTED_VERSION));
} else if (request.getField() == SnepMessage.REQUEST_GET) {
/*發送SnepMessage,SnepMessage來源於CallBack的實現,sendMessage 把SnepMessage轉換成byte[]通過LlcpSocket socket發送數據*/
messenger.sendMessage(callback.doGet(request.getAcceptableLength(),
request.getNdefMessage()));
} else if (request.getField() == SnepMessage.REQUEST_PUT) {
if (DBG) Log.d(TAG, "putting message " + request.toString());
//發送SnepMessage,SnepMessage來源於Callback的實現
messenger.sendMessage(callback.doPut(request.getNdefMessage()));
} else {
if (DBG) Log.d(TAG, "Unknown request (" + request.getField() +")");
messenger.sendMessage(SnepMessage.getMessage(
SnepMessage.RESPONSE_BAD_REQUEST));
}
return true;
}
上面code涉及到CallBack一個回調接口,它實現在P2pLinkManager.java中
final SnepServer.Callback mDefaultSnepCallback = new SnepServer.Callback() {
@Override
public SnepMessage doPut(NdefMessage msg) {
/*該方法中有個EventLogTags.writeNfcNdefReceived 的調用,我始終沒找到它的具體方法實現在哪兒*/
onReceiveComplete(msg);
return SnepMessage.getMessage(SnepMessage.RESPONSE_SUCCESS);
}
@Override
public SnepMessage doGet(int acceptableLength, NdefMessage msg) {
NdefMessage response = mHandoverManager.tryHandoverRequest(msg);
if (response != null) {
onReceiveHandover();
return SnepMessage.getSuccessResponse(response);
} else {
return SnepMessage.getMessage(SnepMessage.RESPONSE_NOT_FOUND);
}
}
};
setp2:啓動NdefPushServer,setp3:啓動EchoServer的過程和setp1:啓動SnepServer過程類似,具體可以參照setp1,在此就不做詳細分析。
以上分析中涉及到SnepServer,NdefPushServer,EchoServer。看下這三個文件中對自己的註釋說明。。
SnepServer:A simple server that accepts NDEF messages pushed to it over an LLCP connection. Those messages are typically set on the client side by using NfcAdapter.enableForegroundNdefPush.通過LLCP接收NDEF 消息,並把消息通過NfcAdapter.enableForegroundNdefPush設置到客戶端。
NdefPushServer:同SnepServer。
EchoServer:EchoServer is an implementation of the echo server that is used in the nfcpy LLCP test suite. Enabling the EchoServer allows to test Android NFC devices against nfcpy,這是code中給的註釋說明,但不知到nfcpy是什麼東西,故不做翻譯了。