[NFC]NFC啓動流程2

正式進入NFCService.java,開始NFC framework探索, jiu~~~~



        接上篇文章內容,進入NfcService後,就開始啓動各種Services,Hold on,一大波代碼馬上到來:

{
        mUserId = ActivityManager.getCurrentUser();
        mContext = nfcApplication;

	//@paul: Tag相關; extend INfcTag;最終調用到NativeNfcTag
        mNfcTagService = new TagService();
		//@paul: 上層APP   調用 NFC  功能時, 中間變量adapter;extend INfcAdaptor;最終調用到NfcAdaptor
	    mNfcAdapter = new NfcAdapterService();
        Log.i(TAG, "Starting NFC service");

        sService = this;
	//@paul: NFC與屏幕解鎖的關係,含OFF / ON_LOCK / ON_UNLOCK
        mScreenStateHelper = new ScreenStateHelper(mContext);
        mContentResolver = mContext.getContentResolver();
	//@paul: 底層Driver  相關的JNI  接口
        mDeviceHost = new NativeNfcManager(mContext, this);
	//@paul: 還不懂
        mNfcUnlockManager = NfcUnlockManager.getInstance();
	//@paul: 和handover  相關接口;主要是bluetooth,  實際上wifi  也是可以實現的
        mHandoverManager = new HandoverManager(mContext);
        boolean isNfcProvisioningEnabled = false;
        try {
            isNfcProvisioningEnabled = mContext.getResources().getBoolean(
                    R.bool.enable_nfc_provisioning);
        } catch (NotFoundException e) {
        }
	//@paul: 設備是否在setup wizard階段支持接收NFC   數據
        if (isNfcProvisioningEnabled) {
            mInProvisionMode = Settings.Secure.getInt(mContentResolver,
                    Settings.Global.DEVICE_PROVISIONED, 0) == 0;
        } else {
            mInProvisionMode = false;
        }
	//@paul: 收到NFC  消息處理流程,  最終調用到dispatchTag()
        mNfcDispatcher = new NfcDispatcher(mContext, mHandoverManager, mInProvisionMode);
	//@paul: 基於LLCP  連接的服務,含NdefPushService/SnepService/P2pEventManager
	//@paul: 此類會定義doPut/doGet, 後續還會提到
	mP2pLinkManager = new P2pLinkManager(mContext, mHandoverManager,
                mDeviceHost.getDefaultLlcpMiu(), mDeviceHost.getDefaultLlcpRwSize());
	//@paul: 獲取shared_pref  信息,一般存儲位置在/data/data/<包名>/shared_prefs
        mPrefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE);
        mPrefsEditor = mPrefs.edit();

	//@paul: 和security相關,主要是讀取解析/etc/nfcee_access.xml文件
        mNfceeAccessControl = new NfceeAccessControl(mContext);

        mState = NfcAdapter.STATE_OFF;
	//@paul: 依prefs  文件定義,檢查NdefPush 是否enable
        mIsNdefPushEnabled = mPrefs.getBoolean(PREF_NDEF_PUSH_ON, NDEF_PUSH_ON_DEFAULT);
        setBeamShareActivityState(mIsNdefPushEnabled);

        mIsDebugBuild = "userdebug".equals(Build.TYPE) || "eng".equals(Build.TYPE);
	//@paul: 電源管理模塊,主要是屏幕狀態與NFC  是否響應有關係
        mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
	//@paul: 獲取WakeLock
	//		步驟:1.獲取powermanager  實例
	//		2.生成實例: new WakeLock
	//		3.通過acquire()  獲取鎖
        mRoutingWakeLock = mPowerManager.newWakeLock(
                PowerManager.PARTIAL_WAKE_LOCK, "NfcService:mRoutingWakeLock");
	//@paul: 屏幕鎖
        mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);

        mScreenState = mScreenStateHelper.checkScreenState();
	//@Paul: 將NFC  加入到系統service中
        ServiceManager.addService(SERVICE_NAME, mNfcAdapter);

        // Intents for all users
        //@paul: 註冊屏幕亮/滅,用戶激活和切換
        IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
        filter.addAction(Intent.ACTION_SCREEN_ON);
        filter.addAction(Intent.ACTION_USER_PRESENT);
        filter.addAction(Intent.ACTION_USER_SWITCHED);
        registerForAirplaneMode(filter);
        mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, null);

        IntentFilter ownerFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
        ownerFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
        mContext.registerReceiver(mOwnerReceiver, ownerFilter);

	//@paul: 關注程序安裝和卸載
        ownerFilter = new IntentFilter();
        ownerFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
        ownerFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
        ownerFilter.addDataScheme("package");
        mContext.registerReceiver(mOwnerReceiver, ownerFilter);

        updatePackageCache();

        PackageManager pm = mContext.getPackageManager();
	//@paul: 判斷系統是否支持卡模擬
        mIsHceCapable = pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION);
        if (mIsHceCapable) {
            mCardEmulationManager = new CardEmulationManager(mContext);
        }
        mForegroundUtils = ForegroundUtils.getInstance();
	//@paul: 開始執行NFC   , 參數TASK_BOOT
        new EnableDisableTask().execute(TASK_BOOT);  // do blocking boot tasks
    }

        看完這麼多的代碼,是不是還不確定各個部分的意義。沒有關係,繼續挖。


1. TagService

        此部分實現的接口都在INfcTag.aidl中定義,接口如下:

{
    int close(int nativeHandle);
    int connect(int nativeHandle, int technology);
    int reconnect(int nativeHandle);
    int[] getTechList(int nativeHandle);
    boolean isNdef(int nativeHandle);
    boolean isPresent(int nativeHandle);
    TransceiveResult transceive(int nativeHandle, in byte[] data, boolean raw);
    NdefMessage ndefRead(int nativeHandle);
    int ndefWrite(int nativeHandle, in NdefMessage msg);
    int ndefMakeReadOnly(int nativeHandle);
    boolean ndefIsWritable(int nativeHandle);
    int formatNdef(int nativeHandle, in byte[] key);
    Tag rediscover(int nativehandle);
    int setTimeout(int technology, int timeout);
    int getTimeout(int technology);
    void resetTimeouts();
    boolean canMakeReadOnly(int ndefType);
    int getMaxTransceiveLength(int technology);
    boolean getExtendedLengthApdusSupported();
}

        其中connect()函數爲例,解釋一下此部分的流程和邏輯,其餘的函數基本上可以參考connect()函數:

        @Override
        public int connect(int nativeHandle, int technology) throws RemoteException {
	    //@paul: 檢查manifest中是否有nfc操作權限
            NfcPermissions.enforceUserPermissions(mContext);

            TagEndpoint tag = null;
	    //@paul: 判斷NFC是否啓動,在執行enableInternal()時,條件爲真
            if (!isNfcEnabled()) {
                return ErrorCodes.ERROR_NOT_INITIALIZED;
            }

            /* find the tag in the hmap */
            tag = (TagEndpoint) findObject(nativeHandle);
            if (tag == null) {
                return ErrorCodes.ERROR_DISCONNECT;
            }
	    //@paul: 判斷Tag是否還在範圍內,NativeNfcTag會自動更新連接的標記
            if (!tag.isPresent()) {
                return ErrorCodes.ERROR_DISCONNECT;
            }

            // Note that on most tags, all technologies are behind a single
            // handle. This means that the connect at the lower levels
            // will do nothing, as the tag is already connected to that handle.
            //@paul: NativeNfcTag中定義了connect函數,最終調用到doConnect()
            if (tag.connect(technology)) {
                return ErrorCodes.SUCCESS;
            } else {
                return ErrorCodes.ERROR_DISCONNECT;
            }
        }

        上述函數中的tag.connect()最終調用到NativeNfcTag.java中的connect,此處的調用就是aidl實現的。 下面以NXP的流程介紹一下NativeNfcTag.java中的connect

    @Override
    public synchronized boolean connect(int technology) {
        return connectWithStatus(technology) == 0;
    }

        看起來還要繼續挖:

    private native int doConnect(int handle);
    public synchronized int connectWithStatus(int technology) {
        if (technology == TagTechnology.NFC_B) {
            // Not supported by PN544
	    //@paul: 芯片特性,不支持怎麼的
            return -1;
        }
        if (mWatchdog != null) {
            mWatchdog.pause();
        }
        int status = -1;
        for (int i = 0; i < mTechList.length; i++) {
            if (mTechList[i] == technology) {
                // Get the handle and connect, if not already connected
                if (mConnectedHandle != mTechHandles[i]) {
                    // We're not yet connected to this handle, there are
                    // a few scenario's here:
                    // 1) We are not connected to anything yet - allow
                    // 2) We are connected to a technology which has
                    //    a different handle (multi-protocol tag); we support
                    //    switching to that.
                    if (mConnectedHandle == -1) {
                        // Not connected yet
			//@paul: 如果是沒有連接過,則直接調用到doConnect()
                        status = doConnect(mTechHandles[i]);
                    } else {
                        // Connect to a tech with a different handle
                        status = reconnectWithStatus(mTechHandles[i]);
                    }
                    if (status == 0) {
                        mConnectedHandle = mTechHandles[i];
                        mConnectedTechIndex = i;
                    }
                } else {
                    ......
                }
                break;
            }
        }
        if (mWatchdog != null) {
            mWatchdog.doResume();
        }
        return status;
    }

        看了這麼多,重要的就是最後的doConnect(),這個是JNI的一個接口:

   {"doConnect", "(I)I",
      (void *)com_android_nfc_NativeNfcTag_doConnect},

        繼續挖吧:

static jint com_android_nfc_NativeNfcTag_doConnect(JNIEnv *e,jobject o, phLibNfc_Handle handle)
{
   jint status;
   struct nfc_jni_callback_data cb_data;
   phLibNfc_sRemoteDevInformation_t* pRemDevInfo = NULL;

   CONCURRENCY_LOCK();

   /* Create the local semaphore */
   if (!nfc_cb_data_init(&cb_data, &pRemDevInfo))
   {
      status = NFCSTATUS_NOT_ENOUGH_MEMORY;
      goto clean_and_return;
   }

   TRACE("phLibNfc_RemoteDev_Connect(RW)");
   REENTRANCE_LOCK();
   storedHandle = handle;
   status = phLibNfc_RemoteDev_Connect(handle, nfc_jni_connect_callback,(void *)&cb_data);
   ......

   /* Connect Status */
   if(status != NFCSTATUS_SUCCESS)
   {
      goto clean_and_return;
   }

   // Success, set poll & act bytes
   set_target_pollBytes(e, o, pRemDevInfo);
   set_target_activationBytes(e, o, pRemDevInfo);

   clean_and_return:
   nfc_cb_data_deinit(&cb_data);
   CONCURRENCY_UNLOCK();
   return status;
}
        好吧,你也不想看了,我也看不到了,最後這些API都是在nxp提供的so中export出來的,目前還看不到源碼。


2. NfcAdaptorService

        此部分定義的接口主要是提供給上層,接口定義在INfcAdaptor.aidl中,目的是透過該接口,可以直接操作Framework中的API,最終調用到JNI層。INfcAdaptor中接口如下:

	{
		//@paul: 獲取NfcService中初始化的mNfcTagService
	    INfcTag getNfcTagInterface();
		//@paul: 獲取NfcService中初始化的mCardEmulationInterface
	    INfcCardEmulation getNfcCardEmulationInterface();
		//@paul: AOSP默認不支持
	    INfcAdapterExtras getNfcAdapterExtrasInterface(in String pkg);
		//@paul: 獲取NFC當前狀態
	    int getState();
		//@paul: 關閉NFC功能
	    boolean disable(boolean saveState);
		//@paul: 啓動NFC功能
	    boolean enable();
		//@paul: 更新prefs中ndef值,同時啓動p2p發送功能service
 	    boolean enableNdefPush();
		//@paul: 更新prefs中ndef值,同時關閉p2p發送功能service
 	    boolean disableNdefPush();
		//@paul: NdefPush功能是否打開
	    boolean isNdefPushEnabled();
		//@paul: 啓動底層polling流程,最終會調用到JNI,到Driver
	    void pausePolling(int timeoutInMs);
	    void resumePolling();
		//@paul: 寫APP時候的常用方法,設置此函數後,收到的消息會只在前臺的APP處理
	    void setForegroundDispatch(in PendingIntent intent,in IntentFilter[] filters, in TechListParcel techLists);
		//@paul: 上層APP設置回調,用於Beam過程中產生shareData	
	    void setAppCallback(in IAppCallback callback);
		//@paul: 啓動Beam流程
	    oneway void invokeBeam();
	    oneway void invokeBeamInternal(in BeamShareData shareData);
		//@paul: 分發收到的tag信息
	    void dispatch(in Tag tag);
	    void setReaderMode (IBinder b, IAppCallback callback, int flags, in Bundle extras);
	    void setP2pModes(int initatorModes, int targetModes);
	    void addNfcUnlockHandler(INfcUnlockHandler unlockHandler, in int[] techList);
	    void removeNfcUnlockHandler(INfcUnlockHandler unlockHandler);
	}


3. ScreenStateHelper

        這個類主要作用是檢查當前屏幕狀態,原因是NFC的一些應用需要在屏滅以及鎖屏的情況下也能應用(例如刷公交卡),主要的函數如下:

int checkScreenState() {
	//TODO: fix deprecated api	
	if (!mPowerManager.isScreenOn()) {
	//@paul: 依據pm提供的接口判斷屏幕是否點亮
		return SCREEN_STATE_OFF;
	} else if (mKeyguardManager.isKeyguardLocked()) {
	//@paul: 依據KeyguardManager判斷是否在解鎖狀態
		return SCREEN_STATE_ON_LOCKED;
	} else {
	//@paul: 上述都不是,則設備處於屏幕解鎖狀態
		return SCREEN_STATE_ON_UNLOCKED;
	}
}


4.NativeNfcManager

        此類是各chip vendor實現,目前AOSP下包含了nxp和nci兩類。下面的例子都是以nxp的接口爲例,nci接口也類似。

        此類的開頭就有以下的信息,表示實例化該類時,先加載且只加載一次libnfc_jni.so:

    static {
        System.loadLibrary("nfc_jni");
    }


        進入構造函數後:

    public NativeNfcManager(Context context, DeviceHostListener listener) {
        mListener = listener;
        initializeNativeStructure();
        mContext = context;
    }

        其中initializeNativeStructure()是native函數,其定義在:

   {"initializeNativeStructure", "()Z",(void *)com_android_nfc_NfcManager_init_native_struc},

        繼續分析:

static jboolean com_android_nfc_NfcManager_init_native_struc(JNIEnv *e, jobject o)
{
   ...
   TRACE("******  Init Native Structure ******");

   /* Initialize native structure */
   nat = (nfc_jni_native_data*)malloc(sizeof(struct nfc_jni_native_data));
   ...


   /* Initialize native cached references */
   //@paul: 定義native層和framework溝通的API
   cached_NfcManager_notifyNdefMessageListeners = e->GetMethodID(cls,
      "notifyNdefMessageListeners","(Lcom/android/nfc/dhimpl/NativeNfcTag;)V");

   cached_NfcManager_notifyLlcpLinkActivation = e->GetMethodID(cls,
      "notifyLlcpLinkActivation","(Lcom/android/nfc/dhimpl/NativeP2pDevice;)V");

   cached_NfcManager_notifyLlcpLinkDeactivated = e->GetMethodID(cls,
      "notifyLlcpLinkDeactivated","(Lcom/android/nfc/dhimpl/NativeP2pDevice;)V");

   cached_NfcManager_notifyRfFieldActivated = e->GetMethodID(cls,
      "notifyRfFieldActivated", "()V");

   cached_NfcManager_notifyRfFieldDeactivated = e->GetMethodID(cls,
      "notifyRfFieldDeactivated", "()V");

   if(nfc_jni_cache_object(e,"com/android/nfc/dhimpl/NativeNfcTag",&(nat->cached_NfcTag)) == -1)
   {
      ALOGD("Native Structure initialization failed");
      return FALSE;
   }

   if(nfc_jni_cache_object(e,"com/android/nfc/dhimpl/NativeP2pDevice",&(nat->cached_P2pDevice)) == -1)
   {
      ALOGD("Native Structure initialization failed");
      return FALSE;
   }
   TRACE("****** Init Native Structure OK ******");
   return TRUE;

}

        在以其中cached_NfcManager_notifyNdefMessageListeners引用爲例,該引用在nfc_jni_Discovery_notification_callback中以下列方式被調用,從而將底層的消息notify到上層APP:

         /* Notify manager that new a tag was found */
         e->CallVoidMethod(nat->manager, cached_NfcManager_notifyNdefMessageListeners, tag.get());
         if(e->ExceptionCheck())
         {
            ALOGE("Exception occurred");
            kill_client(nat);
         }

        以其中enableDiscovery()函數爲例,說明一下該類的基本操作流程:

    //@paul: native接口,
    private native void doEnableDiscovery(int techMask,
                                          boolean enableLowPowerPolling,
                                          boolean enableReaderMode,
                                          boolean restart);
    @Override
    public void enableDiscovery(NfcDiscoveryParameters params, boolean restart) {
        doEnableDiscovery(params.getTechMask(), params.shouldEnableLowPowerDiscovery(),params.shouldEnableReaderMode(), restart);
    }


4.HandoverManager

        此類主要負責NFC到其他傳輸媒介的跳轉,例如Wi-Fi/BT,只是目前AOSP只有是做BT的跳轉。Wi-Fi還沒有定義Spec,所以還沒有這部分的代碼。關於BT Handover的spec,可以參考NFC簡單介紹中Spec下載章節。


        後續會繼續講解Handover的流程,此部分就不做詳細介紹。


5.NfcDispatcher

        此類主要是收到底層Tag消息後,依據tag的類型進行內容解析和數據分發。

public int dispatchTag(Tag tag) {
	...
	
	//@paul: APP在調用setForegroundDispatch()時,會賦值下列變量
	synchronized (this) {
		overrideFilters = mOverrideFilters;
		overrideIntent = mOverrideIntent;
		overrideTechLists = mOverrideTechLists;
		provisioningOnly = mProvisioningOnly;
	}

	//@paul: 屏幕解鎖相關流程
	boolean screenUnlocked = false;
	if (!provisioningOnly &&
			mScreenStateHelper.checkScreenState() == ScreenStateHelper.SCREEN_STATE_ON_LOCKED) {
		screenUnlocked = handleNfcUnlock(tag);
		if (!screenUnlocked) {
			return DISPATCH_FAIL;
		}
	}	
	...
	
	//@paul: 如果前臺Activity啓動分發功能,則只需要處理前臺分發相關工作即可
	if (tryOverrides(dispatch, tag, message, overrideIntent, overrideFilters,
			overrideTechLists)) {
		return screenUnlocked ? DISPATCH_UNLOCK : DISPATCH_SUCCESS;
	}

	//@paul: 判斷是否爲Handover事件
	if (mHandoverManager.tryHandover(message)) {
		if (DBG) Log.i(TAG, "matched BT HANDOVER");
		return screenUnlocked ? DISPATCH_UNLOCK : DISPATCH_SUCCESS;
	}

	//@paul: 判斷是否爲Wifi的handover
	if (NfcWifiProtectedSetup.tryNfcWifiSetup(ndef, mContext)) {
		if (DBG) Log.i(TAG, "matched NFC WPS TOKEN");
		return screenUnlocked ? DISPATCH_UNLOCK : DISPATCH_SUCCESS;
	}

	//@paul: 判斷是否爲ACTION_NDEF_DISCOVERD
	if (tryNdef(dispatch, message, provisioningOnly)) {
		return screenUnlocked ? DISPATCH_UNLOCK : DISPATCH_SUCCESS;
	}
	//@paul: 只有在NDEF格式下,纔會判斷此流程
	if (screenUnlocked) {
		// We only allow NDEF-based mimeType matching in case of an unlock
		return DISPATCH_UNLOCK;
	}
	if (provisioningOnly) {
		// We only allow NDEF-based mimeType matching
		return DISPATCH_FAIL;
	}

	//@paul: 判斷是否爲ACTION_TECH_DISCOVERD
	if (tryTech(dispatch, tag)) {
		return DISPATCH_SUCCESS;
	}
	
	//@paul: 設置intent爲ACTION_TAG_DISCOVERD
	dispatch.setTagIntent();
	//@paul: 查詢對ACTION_TAG_DISCOVERD感興趣的activity,並嘗試啓動
	if (dispatch.tryStartActivity()) {
		if (DBG) Log.i(TAG, "matched TAG");
		return DISPATCH_SUCCESS;
	}

	if (DBG) Log.i(TAG, "no match");
	return DISPATCH_FAIL;
}

6.P2pLinkManager

        此類主要包含基於LLCP連接的server,構造函數中會創建後續需要的類:

public P2pLinkManager(Context context, HandoverManager handoverManager, int defaultMiu,int defaultRwSize) {
	//@paul: 創建NdefPushServer()
	mNdefPushServer = new NdefPushServer(NDEFPUSH_SAP, mNppCallback);
	//@paul: 創建SnepServer()
	mDefaultSnepServer = new SnepServer(mDefaultSnepCallback, defaultMiu, defaultRwSize);
	//@paul: 創建HandoverServer()
	mHandoverServer = new HandoverServer(HANDOVER_SAP, handoverManager, mHandoverCallback);
	//@paul: 創建EchoServer()
	if (ECHOSERVER_ENABLED) {
		mEchoServer = new EchoServer();
	} else {
		mEchoServer = null;
	}
	mPackageManager = context.getPackageManager();
	mContext = context;
	//@paul: 創建P2pEventManager()
	mEventListener = new P2pEventManager(context, this);
	mHandler = new Handler(this);
	...
 }


        其中會分別創建NdefPushServer,SnepServer,HandoverServer,P2pEventManager這幾個重要類。

        NdefPushServer:啓動NPP Server,等待Client連接

        SnepServer:啓動NPP Server,等待Client連接

        HandoverServer:啓動Handover Server,等待Client連接

        P2pEventManager: 啓動Event Manager,用於將底層消息notify到UI或者上層APP


        下面分別以SnepServer,P2pEventManager爲例,簡單說明一下流程(也會補充一下handle的流程)。


        SnepServer的構造函數調用後,會被調用到啓動函數start():

//@paul: 啓動SNEP   server
public void start() {
	synchronized (SnepServer.this) {
		if (DBG) Log.d(TAG, "start, thread = " + mServerThread);
		if (mServerThread == null) {
			if (DBG) Log.d(TAG, "starting new server thread");
			mServerThread = new ServerThread();
			//@paul: ServerThread.run()
			mServerThread.start();
			mServerRunning = true;
		}
	}
}


        其中ServerThread流程如下:

@Override
public void run() {
	...
	while (threadRunning) {
		if (DBG) Log.d(TAG, "about create LLCP service socket");
		try {
			synchronized (SnepServer.this) {
				//@paul: 創建llcp   服務端socket
				//@paul: 包含創建socket,綁定並監聽socket
				mServerSocket = NfcService.getInstance().createLlcpServerSocket(mServiceSap,
						mServiceName, mMiu, mRwSize, 1024);
			}
			...
			while (threadRunning) {
				...
				if (DBG) Log.d(TAG, "about to accept");
				//@paul: 阻塞等待客戶端連接
				//@paul: 一個server  端,可以有多個客戶端連接
				//@paul: 每次client 端連接都會創建新的thread
				LlcpSocket communicationSocket = serverSocket.accept();
				if (DBG) Log.d(TAG, "accept returned " + communicationSocket);
				if (communicationSocket != null) {
					int fragmentLength = (mFragmentLength == -1) ?
							mMiu : Math.min(mMiu, mFragmentLength);
					//@paul: 一旦有客戶端請求連接
					new ConnectionThread(communicationSocket, fragmentLength).start();
				}
				...
			}
			if (DBG) Log.d(TAG, "stop running");
		} catch (LlcpException e) {
			Log.e(TAG, "llcp error", e);
		} catch (IOException e) {
			Log.e(TAG, "IO error", e);
		} finally {
					...
					try {
						mServerSocket.close();
					} catch (IOException e) {
						// ignore
					}
					mServerSocket = null;
				}
			}
		}
		...
	}
}

        一旦有client端來連接,就會調用到ConnectionThread的run()函數:

ConnectionThread(LlcpSocket socket, int fragmentLength) {
	super(TAG);
	mSock = socket;
	//@paul: 創建SnepMessenger 消息處理類
	mMessager = new SnepMessenger(false, socket, fragmentLength);
}

@Override
public void run() {
	if (DBG) Log.d(TAG, "starting connection thread");
	try {
		...
		while (running) {
			//@paul: 每次只要有消息進來,就會進入消息處理流程handleRequest
			//@paul:後續還會說明handleRequest,此部分不多說明
			if (!handleRequest(mMessager, mCallback)) {
				break;
			}
			...
		}
	} catch (IOException e) {
		...
	}
	...
}

        接下來就是P2pEventManager,此類只要是將底層的消息notify給上層,在其構造函數中,最重要的信息如下:

public P2pEventManager(Context context, P2pEventListener.Callback callback) {
	...
	final int uiModeType = mContext.getResources().getConfiguration().uiMode
			& Configuration.UI_MODE_TYPE_MASK;
	if (uiModeType == Configuration.UI_MODE_TYPE_APPLIANCE) {
		// "Appliances" don't intrinsically have a way of confirming this, so we
		// don't use the UI and just autoconfirm where necessary.
		// Don't instantiate SendUi or else we'll use memory and never reclaim it.
		mSendUi = null;
	} else {
		//@paul: 創建SendUI類,實現與UI層的溝通
		mSendUi = new SendUi(context, this);
	}
}
        此類中主要實現了以下函數,函數具體信息以後介紹p2p的時候會舉例說明:

public void onP2pInRange()
public void onP2pNfcTapRequested()
public void onP2pTimeoutWaitingForLink()
public void onP2pSendConfirmationRequested()
public void onP2pSendComplete()
public void onP2pHandoverNotSupported()
public void onP2pReceiveComplete(boolean playSound)
public void onP2pOutOfRange()
public void onSendConfirmed()
public void onCanceled()
public void onP2pSendDebounce()
public void onP2pResumeSend()

        前面也有提到,P2pLinkManager中會實例化一個handle,那handler的作用是什麼呢?這時候就需要注意到P2pLinkManager實現的方式:

class P2pLinkManager implements Handler.Callback, P2pEventListener.Callback {
	...
}

        同時發現代碼中出現了handleMessage(),其內容爲:

@Override
public boolean handleMessage(Message msg) {
	switch (msg.what) {
		case MSG_START_ECHOSERVER:
			...
		case MSG_STOP_ECHOSERVER:
			...
		case MSG_WAIT_FOR_LINK_TIMEOUT:
			...
		case MSG_DEBOUNCE_TIMEOUT:
			...
		case MSG_RECEIVE_HANDOVER:
			...
		case MSG_RECEIVE_COMPLETE:
			...
		case MSG_HANDOVER_NOT_SUPPORTED:
			...
		case MSG_SEND_COMPLETE:
			...
	}
	return true;
}

        我們不禁又要問,那這些message都是從哪裏傳遞上來的呢?以MSG_SEND_COMPLETE爲例,在P2pLinkManager.java中:

    void onReceiveComplete(NdefMessage msg) {
        // Make callbacks on UI thread
        mHandler.obtainMessage(MSG_RECEIVE_COMPLETE, msg).sendToTarget();
    }


        這樣看是底層有確定接收完當前的文件,就會notify給上層(->Framework->App).


7. NfceeAccessControl *

        從代碼流程看,只是去讀取並解析/etc/nfcee_access.xml文件。此處目前還不是很懂實際的應用場景,先跳過。


8.CardEmulationManager *

        此部分目前還沒有詳細研究,先跳過。


9.然後呢,然後發現就只有下面這一句了:

EnableDisableTask().execute(TASK_BOOT)
       

        那我們看看這個函數做什麼了?

@Override
protected Void doInBackground(Integer... params) {
	// Sanity check mState
	...

	/* AsyncTask sets this thread to THREAD_PRIORITY_BACKGROUND,
	 * override with the default. THREAD_PRIORITY_BACKGROUND causes
	 * us to service software I2C too slow for firmware download
	 * with the NXP PN544.
	 * TODO: move this to the DAL I2C layer in libnfc-nxp, since this
	 * problem only occurs on I2C platforms using PN544
	 */
	Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);

	switch (params[0].intValue()) {
		case TASK_ENABLE:
			//@paul: 如果傳入參數是enable,那就直接初始化NFC芯片等,否則
			enableInternal();
			break;
		case TASK_DISABLE:
			//@paul: 否則關閉NFC
			disableInternal();
			break;
		case TASK_BOOT:
			//@paul: 第一次流程上會進入到這裏
			Log.d(TAG, "checking on firmware download");
			//@paul: 檢查prefs中定義的PREF_AIRPLANE_OVERRIDE的值,AOSP沒有定義這個值,即爲false
			boolean airplaneOverride = mPrefs.getBoolean(PREF_AIRPLANE_OVERRIDE, false);
			//@paul:判斷prefs中定義的PREF_NFC_ON,AOSP沒有定義這個值,即爲NFC_ON_DEFAULT
			//@paul:依據Setting.System中設定,判斷mIsAirplaneSensitive(默認true),isAirplaneModeOn(默認false)
			if (mPrefs.getBoolean(PREF_NFC_ON, NFC_ON_DEFAULT) &&
					(!mIsAirplaneSensitive || !isAirplaneModeOn() || airplaneOverride)) {
				Log.d(TAG, "NFC is on. Doing normal stuff");
				//@paul: 默認NFC打開,開始激活NFC  
				enableInternal();
			} else {
				Log.d(TAG, "NFC is off.  Checking firmware version");
				//@paul: 關閉狀態則檢查是否要更新fireware
				mDeviceHost.checkFirmware();
			}
			//@paul: 更新prefs中的PREF_FIRST_BOOT值
			if (mPrefs.getBoolean(PREF_FIRST_BOOT, true)) {
				Log.i(TAG, "First Boot");
				mPrefsEditor.putBoolean(PREF_FIRST_BOOT, false);
				mPrefsEditor.apply();
			}
			break;
	}

	// Restore default AsyncTask priority
	Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
	return null;
}

        一般來說,流程會進入enableInternal()中,你們可能着急了,這裏面做什麼了呢?
/**
 * Enable NFC adapter functions.
 * Does not toggle preferences.
 */
boolean enableInternal() {
	Log.i(TAG, "Enabling NFC");
	...
	
	try {
		...
		try {
			//@paul: 執行DH.initialize(),芯片初始化
			if (!mDeviceHost.initialize()) {
				Log.w(TAG, "Error enabling NFC");
				updateState(NfcAdapter.STATE_OFF);
				return false;
			}
		} finally {
			...
		}
	} 
	...
	synchronized (NfcService.this) {
		...
		//@paul: 依據傳入值,判斷啓動對應服務
		//@paul: mIsNdefPushEnabled由系統設定值確定
		mP2pLinkManager.enableDisable(mIsNdefPushEnabled, true);
		updateState(NfcAdapter.STATE_ON);
	}
	//@paul: 設置啓動,完成,錯誤時對應的聲音文件
	initSoundPool();

	/* Start polling loop */
	//@paul: 啓動NFC底層輪詢
	applyRouting(true);
	return true;
}


        applyRouting()之後,就啓動底層的polling機制,如果底層偵測到有NFC設備靠近,就會進入對應的處理流程。


        到目前爲止,基本上NFC的功能都有啓動,剩下的工作就是有不同的設備接近的事情,進入不同的流程進行處理。


        後續會從Tag以及P2P兩個方面進行系統流程的分析。


        前文提到的CardEmulation 以及NFCEE_ACCESS部分會看後續學習的情況進行補充。

        





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