NFC學習——NFC Enable 過程分析(三)

        這篇文章用來分析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是什麼東西,故不做翻譯了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章