[NFC]NFC启动流程2

正式进入NFCService.Java,开始NFC framework探索, jiu~~~~



        接上篇文章内容,进入NfcService后,就开始启动各种Services,Hold on,一大波代码马上到来:

[java]  view plain  copy
 print ?
  1. {  
  2.         mUserId = ActivityManager.getCurrentUser();  
  3.         mContext = nfcApplication;  
  4.   
  5.     //@paul: Tag相关; extend INfcTag;最终调用到NativeNfcTag  
  6.         mNfcTagService = new TagService();  
  7.         //@paul: 上层APP   调用 NFC  功能时, 中间变量adapter;extend INfcAdaptor;最终调用到NfcAdaptor  
  8.         mNfcAdapter = new NfcAdapterService();  
  9.         Log.i(TAG, "Starting NFC service");  
  10.   
  11.         sService = this;  
  12.     //@paul: NFC与屏幕解锁的关系,含OFF / ON_LOCK / ON_UNLOCK  
  13.         mScreenStateHelper = new ScreenStateHelper(mContext);  
  14.         mContentResolver = mContext.getContentResolver();  
  15.     //@paul: 底层Driver  相关的JNI  接口  
  16.         mDeviceHost = new NativeNfcManager(mContext, this);  
  17.     //@paul: 还不懂  
  18.         mNfcUnlockManager = NfcUnlockManager.getInstance();  
  19.     //@paul: 和handover  相关接口;主要是bluetooth,  实际上wifi  也是可以实现的  
  20.         mHandoverManager = new HandoverManager(mContext);  
  21.         boolean isNfcProvisioningEnabled = false;  
  22.         try {  
  23.             isNfcProvisioningEnabled = mContext.getResources().getBoolean(  
  24.                     R.bool.enable_nfc_provisioning);  
  25.         } catch (NotFoundException e) {  
  26.         }  
  27.     //@paul: 设备是否在setup wizard阶段支持接收NFC   数据  
  28.         if (isNfcProvisioningEnabled) {  
  29.             mInProvisionMode = Settings.Secure.getInt(mContentResolver,  
  30.                     Settings.Global.DEVICE_PROVISIONED, 0) == 0;  
  31.         } else {  
  32.             mInProvisionMode = false;  
  33.         }  
  34.     //@paul: 收到NFC  消息处理流程,  最终调用到dispatchTag()  
  35.         mNfcDispatcher = new NfcDispatcher(mContext, mHandoverManager, mInProvisionMode);  
  36.     //@paul: 基于LLCP  连接的服务,含NdefPushService/SnepService/P2pEventManager  
  37.     //@paul: 此类会定义doPut/doGet, 后续还会提到  
  38.     mP2pLinkManager = new P2pLinkManager(mContext, mHandoverManager,  
  39.                 mDeviceHost.getDefaultLlcpMiu(), mDeviceHost.getDefaultLlcpRwSize());  
  40.     //@paul: 获取shared_pref  信息,一般存储位置在/data/data/<包名>/shared_prefs  
  41.         mPrefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE);  
  42.         mPrefsEditor = mPrefs.edit();  
  43.   
  44.     //@paul: 和security相关,主要是读取解析/etc/nfcee_access.xml文件  
  45.         mNfceeAccessControl = new NfceeAccessControl(mContext);  
  46.   
  47.         mState = NfcAdapter.STATE_OFF;  
  48.     //@paul: 依prefs  文件定义,检查NdefPush 是否enable  
  49.         mIsNdefPushEnabled = mPrefs.getBoolean(PREF_NDEF_PUSH_ON, NDEF_PUSH_ON_DEFAULT);  
  50.         setBeamShareActivityState(mIsNdefPushEnabled);  
  51.   
  52.         mIsDebugBuild = "userdebug".equals(Build.TYPE) || "eng".equals(Build.TYPE);  
  53.     //@paul: 电源管理模块,主要是屏幕状态与NFC  是否响应有关系  
  54.         mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);  
  55.     //@paul: 获取WakeLock  
  56.     //      步骤:1.获取powermanager  实例  
  57.     //      2.生成实例: new WakeLock  
  58.     //      3.通过acquire()  获取锁  
  59.         mRoutingWakeLock = mPowerManager.newWakeLock(  
  60.                 PowerManager.PARTIAL_WAKE_LOCK, "NfcService:mRoutingWakeLock");  
  61.     //@paul: 屏幕锁  
  62.         mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);  
  63.         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);  
  64.   
  65.         mScreenState = mScreenStateHelper.checkScreenState();  
  66.     //@Paul: 将NFC  加入到系统service中  
  67.         ServiceManager.addService(SERVICE_NAME, mNfcAdapter);  
  68.   
  69.         // Intents for all users  
  70.         //@paul: 注册屏幕亮/灭,用户激活和切换  
  71.         IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);  
  72.         filter.addAction(Intent.ACTION_SCREEN_ON);  
  73.         filter.addAction(Intent.ACTION_USER_PRESENT);  
  74.         filter.addAction(Intent.ACTION_USER_SWITCHED);  
  75.         registerForAirplaneMode(filter);  
  76.         mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, nullnull);  
  77.   
  78.         IntentFilter ownerFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);  
  79.         ownerFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);  
  80.         mContext.registerReceiver(mOwnerReceiver, ownerFilter);  
  81.   
  82.     //@paul: 关注程序安装和卸载  
  83.         ownerFilter = new IntentFilter();  
  84.         ownerFilter.addAction(Intent.ACTION_PACKAGE_ADDED);  
  85.         ownerFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);  
  86.         ownerFilter.addDataScheme("package");  
  87.         mContext.registerReceiver(mOwnerReceiver, ownerFilter);  
  88.   
  89.         updatePackageCache();  
  90.   
  91.         PackageManager pm = mContext.getPackageManager();  
  92.     //@paul: 判断系统是否支持卡模拟  
  93.         mIsHceCapable = pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION);  
  94.         if (mIsHceCapable) {  
  95.             mCardEmulationManager = new CardEmulationManager(mContext);  
  96.         }  
  97.         mForegroundUtils = ForegroundUtils.getInstance();  
  98.     //@paul: 开始执行NFC   , 参数TASK_BOOT  
  99.         new EnableDisableTask().execute(TASK_BOOT);  // do blocking boot tasks  
  100.     }  

        看完这么多的代码,是不是还不确定各个部分的意义。没有关系,继续挖。


1. TagService

        此部分实现的接口都在INfcTag.aidl中定义,接口如下:

[cpp]  view plain  copy
 print ?
  1. {  
  2.     int close(int nativeHandle);  
  3.     int connect(int nativeHandle, int technology);  
  4.     int reconnect(int nativeHandle);  
  5.     int[] getTechList(int nativeHandle);  
  6.     boolean isNdef(int nativeHandle);  
  7.     boolean isPresent(int nativeHandle);  
  8.     TransceiveResult transceive(int nativeHandle, in byte[] data, boolean raw);  
  9.     NdefMessage ndefRead(int nativeHandle);  
  10.     int ndefWrite(int nativeHandle, in NdefMessage msg);  
  11.     int ndefMakeReadOnly(int nativeHandle);  
  12.     boolean ndefIsWritable(int nativeHandle);  
  13.     int formatNdef(int nativeHandle, in byte[] key);  
  14.     Tag rediscover(int nativehandle);  
  15.     int setTimeout(int technology, int timeout);  
  16.     int getTimeout(int technology);  
  17.     void resetTimeouts();  
  18.     boolean canMakeReadOnly(int ndefType);  
  19.     int getMaxTransceiveLength(int technology);  
  20.     boolean getExtendedLengthApdusSupported();  
  21. }  

        以其中connect()函数为例,解释一下此部分的流程和逻辑,其余的函数基本上可以参考connect()函数:

[java]  view plain  copy
 print ?
  1.    @Override  
  2.    public int connect(int nativeHandle, int technology) throws RemoteException {  
  3. //@paul: 检查manifest中是否有nfc操作权限  
  4.        NfcPermissions.enforceUserPermissions(mContext);  
  5.   
  6.        TagEndpoint tag = null;  
  7. //@paul: 判断NFC是否启动,在执行enableInternal()时,条件为真  
  8.        if (!isNfcEnabled()) {  
  9.            return ErrorCodes.ERROR_NOT_INITIALIZED;  
  10.        }  
  11.   
  12.        /* find the tag in the hmap */  
  13.        tag = (TagEndpoint) findObject(nativeHandle);  
  14.        if (tag == null) {  
  15.            return ErrorCodes.ERROR_DISCONNECT;  
  16.        }  
  17. //@paul: 判断Tag是否还在范围内,NativeNfcTag会自动更新连接的标记  
  18.        if (!tag.isPresent()) {  
  19.            return ErrorCodes.ERROR_DISCONNECT;  
  20.        }  
  21.   
  22.        // Note that on most tags, all technologies are behind a single  
  23.        // handle. This means that the connect at the lower levels  
  24.        // will do nothing, as the tag is already connected to that handle.  
  25.        //@paul: NativeNfcTag中定义了connect函数,最终调用到doConnect()  
  26.        if (tag.connect(technology)) {  
  27.            return ErrorCodes.SUCCESS;  
  28.        } else {  
  29.            return ErrorCodes.ERROR_DISCONNECT;  
  30.        }  
  31.    }  

        上述函数中的tag.connect()最终调用到NativeNfcTag.java中的connect,此处的调用就是aidl实现的。 下面以NXP的流程介绍一下NativeNfcTag.java中的connect。

[java]  view plain  copy
 print ?
  1. @Override  
  2. public synchronized boolean connect(int technology) {  
  3.     return connectWithStatus(technology) == 0;  
  4. }  

        看起来还要继续挖:

[java]  view plain  copy
 print ?
  1. private native int doConnect(int handle);  
  2. public synchronized int connectWithStatus(int technology) {  
  3.     if (technology == TagTechnology.NFC_B) {  
  4.         // Not supported by PN544  
  5.  //@paul: 芯片特性,不支持怎么的  
  6.         return -1;  
  7.     }  
  8.     if (mWatchdog != null) {  
  9.         mWatchdog.pause();  
  10.     }  
  11.     int status = -1;  
  12.     for (int i = 0; i < mTechList.length; i++) {  
  13.         if (mTechList[i] == technology) {  
  14.             // Get the handle and connect, if not already connected  
  15.             if (mConnectedHandle != mTechHandles[i]) {  
  16.                 // We're not yet connected to this handle, there are  
  17.                 // a few scenario's here:  
  18.                 // 1) We are not connected to anything yet - allow  
  19.                 // 2) We are connected to a technology which has  
  20.                 //    a different handle (multi-protocol tag); we support  
  21.                 //    switching to that.  
  22.                 if (mConnectedHandle == -1) {  
  23.                     // Not connected yet  
  24. /@paul: 如果是没有连接过,则直接调用到doConnect()  
  25.                     status = doConnect(mTechHandles[i]);  
  26.                 } else {  
  27.                     // Connect to a tech with a different handle  
  28.                     status = reconnectWithStatus(mTechHandles[i]);  
  29.                 }  
  30.                 if (status == 0) {  
  31.                     mConnectedHandle = mTechHandles[i];  
  32.                     mConnectedTechIndex = i;  
  33.                 }  
  34.             } else {  
  35.                 ......  
  36.             }  
  37.             break;  
  38.         }  
  39.     }  
  40.     if (mWatchdog != null) {  
  41.         mWatchdog.doResume();  
  42.     }  
  43.     return status;  
  44. }  

        看了这么多,重要的就是最后的doConnect(),这个是JNI的一个接口:

[cpp]  view plain  copy
 print ?
  1. {"doConnect""(I)I",  
  2.    (void *)com_android_nfc_NativeNfcTag_doConnect},  

        继续挖吧:

[cpp]  view plain  copy
 print ?
  1. static jint com_android_nfc_NativeNfcTag_doConnect(JNIEnv *e,jobject o, phLibNfc_Handle handle)  
  2. {  
  3.    jint status;  
  4.    struct nfc_jni_callback_data cb_data;  
  5.    phLibNfc_sRemoteDevInformation_t* pRemDevInfo = NULL;  
  6.   
  7.    CONCURRENCY_LOCK();  
  8.   
  9.    /* Create the local semaphore */  
  10.    if (!nfc_cb_data_init(&cb_data, &pRemDevInfo))  
  11.    {  
  12.       status = NFCSTATUS_NOT_ENOUGH_MEMORY;  
  13.       goto clean_and_return;  
  14.    }  
  15.   
  16.    TRACE("phLibNfc_RemoteDev_Connect(RW)");  
  17.    REENTRANCE_LOCK();  
  18.    storedHandle = handle;  
  19.    status = phLibNfc_RemoteDev_Connect(handle, nfc_jni_connect_callback,(void *)&cb_data);  
  20.    ......  
  21.   
  22.    /* Connect Status */  
  23.    if(status != NFCSTATUS_SUCCESS)  
  24.    {  
  25.       goto clean_and_return;  
  26.    }  
  27.   
  28.    // Success, set poll & act bytes  
  29.    set_target_pollBytes(e, o, pRemDevInfo);  
  30.    set_target_activationBytes(e, o, pRemDevInfo);  
  31.   
  32.    clean_and_return:  
  33.    nfc_cb_data_deinit(&cb_data);  
  34.    CONCURRENCY_UNLOCK();  
  35.    return status;  
  36. }  
        好吧,你也不想看了,我也看不到了,最后这些API都是在nxp提供的so中export出来的,目前还看不到源码。


2. NfcAdaptorService

        此部分定义的接口主要是提供给上层,接口定义在INfcAdaptor.aidl中,目的是透过该接口,可以直接操作Framework中的API,最终调用到JNI层。INfcAdaptor中接口如下:

[java]  view plain  copy
 print ?
  1. {  
  2.     //@paul: 获取NfcService中初始化的mNfcTagService  
  3.     INfcTag getNfcTagInterface();  
  4.     //@paul: 获取NfcService中初始化的mCardEmulationInterface  
  5.     INfcCardEmulation getNfcCardEmulationInterface();  
  6.     //@paul: AOSP默认不支持  
  7.     INfcAdapterExtras getNfcAdapterExtrasInterface(in String pkg);  
  8.     //@paul: 获取NFC当前状态  
  9.     int getState();  
  10.     //@paul: 关闭NFC功能  
  11.     boolean disable(boolean saveState);  
  12.     //@paul: 启动NFC功能  
  13.     boolean enable();  
  14.     //@paul: 更新prefs中ndef值,同时启动p2p发送功能service  
  15.         boolean enableNdefPush();  
  16.     //@paul: 更新prefs中ndef值,同时关闭p2p发送功能service  
  17.         boolean disableNdefPush();  
  18.     //@paul: NdefPush功能是否打开  
  19.     boolean isNdefPushEnabled();  
  20.     //@paul: 启动底层polling流程,最终会调用到JNI,到Driver  
  21.     void pausePolling(int timeoutInMs);  
  22.     void resumePolling();  
  23.     //@paul: 写APP时候的常用方法,设置此函数后,收到的消息会只在前台的APP处理  
  24.     void setForegroundDispatch(in PendingIntent intent,in IntentFilter[] filters, in TechListParcel techLists);  
  25.     //@paul: 上层APP设置回调,用于Beam过程中产生shareData   
  26.     void setAppCallback(in IAppCallback callback);  
  27.     //@paul: 启动Beam流程  
  28.     oneway void invokeBeam();  
  29.     oneway void invokeBeamInternal(in BeamShareData shareData);  
  30.     //@paul: 分发收到的tag信息  
  31.     void dispatch(in Tag tag);  
  32.     void setReaderMode (IBinder b, IAppCallback callback, int flags, in Bundle extras);  
  33.     void setP2pModes(int initatorModes, int targetModes);  
  34.     void addNfcUnlockHandler(INfcUnlockHandler unlockHandler, in int[] techList);  
  35.     void removeNfcUnlockHandler(INfcUnlockHandler unlockHandler);  
  36. }  


3. ScreenStateHelper

        这个类主要作用是检查当前屏幕状态,原因是NFC的一些应用需要在屏灭以及锁屏的情况下也能应用(例如刷公交卡),主要的函数如下:

[java]  view plain  copy
 print ?
  1. int checkScreenState() {  
  2.     //TODO: fix deprecated api    
  3.     if (!mPowerManager.isScreenOn()) {  
  4.     //@paul: 依据pm提供的接口判断屏幕是否点亮  
  5.         return SCREEN_STATE_OFF;  
  6.     } else if (mKeyguardManager.isKeyguardLocked()) {  
  7.     //@paul: 依据KeyguardManager判断是否在解锁状态  
  8.         return SCREEN_STATE_ON_LOCKED;  
  9.     } else {  
  10.     //@paul: 上述都不是,则设备处于屏幕解锁状态  
  11.         return SCREEN_STATE_ON_UNLOCKED;  
  12.     }  
  13. }  


4.NativeNfcManager

        此类是各chip vendor实现,目前AOSP下包含了nxp和nci两类。下面的例子都是以nxp的接口为例,nci接口也类似。

        此类的开头就有以下的信息,表示实例化该类时,先加载且只加载一次libnfc_jni.so:

[java]  view plain  copy
 print ?
  1. static {  
  2.     System.loadLibrary("nfc_jni");  
  3. }  


        进入构造函数后:

[java]  view plain  copy
 print ?
  1. public NativeNfcManager(Context context, DeviceHostListener listener) {  
  2.     mListener = listener;  
  3.     initializeNativeStructure();  
  4.     mContext = context;  
  5. }  

        其中initializeNativeStructure()是native函数,其定义在:

[java]  view plain  copy
 print ?
  1. {"initializeNativeStructure""()Z",(void *)com_android_nfc_NfcManager_init_native_struc},  

        继续分析:

[cpp]  view plain  copy
 print ?
  1. static jboolean com_android_nfc_NfcManager_init_native_struc(JNIEnv *e, jobject o)  
  2. {  
  3.    ...  
  4.    TRACE("******  Init Native Structure ******");  
  5.   
  6.    /* Initialize native structure */  
  7.    nat = (nfc_jni_native_data*)malloc(sizeof(struct nfc_jni_native_data));  
  8.    ...  
  9.   
  10.   
  11.    /* Initialize native cached references */  
  12.    //@paul: 定义native层和framework沟通的API  
  13.    cached_NfcManager_notifyNdefMessageListeners = e->GetMethodID(cls,  
  14.       "notifyNdefMessageListeners","(Lcom/android/nfc/dhimpl/NativeNfcTag;)V");  
  15.   
  16.    cached_NfcManager_notifyLlcpLinkActivation = e->GetMethodID(cls,  
  17.       "notifyLlcpLinkActivation","(Lcom/android/nfc/dhimpl/NativeP2pDevice;)V");  
  18.   
  19.    cached_NfcManager_notifyLlcpLinkDeactivated = e->GetMethodID(cls,  
  20.       "notifyLlcpLinkDeactivated","(Lcom/android/nfc/dhimpl/NativeP2pDevice;)V");  
  21.   
  22.    cached_NfcManager_notifyRfFieldActivated = e->GetMethodID(cls,  
  23.       "notifyRfFieldActivated""()V");  
  24.   
  25.    cached_NfcManager_notifyRfFieldDeactivated = e->GetMethodID(cls,  
  26.       "notifyRfFieldDeactivated""()V");  
  27.   
  28.    if(nfc_jni_cache_object(e,"com/android/nfc/dhimpl/NativeNfcTag",&(nat->cached_NfcTag)) == -1)  
  29.    {  
  30.       ALOGD("Native Structure initialization failed");  
  31.       return FALSE;  
  32.    }  
  33.   
  34.    if(nfc_jni_cache_object(e,"com/android/nfc/dhimpl/NativeP2pDevice",&(nat->cached_P2pDevice)) == -1)  
  35.    {  
  36.       ALOGD("Native Structure initialization failed");  
  37.       return FALSE;  
  38.    }  
  39.    TRACE("****** Init Native Structure OK ******");  
  40.    return TRUE;  
  41.   
  42. }  

        在以其中cached_NfcManager_notifyNdefMessageListeners引用为例,该引用在nfc_jni_Discovery_notification_callback中以下列方式被调用,从而将底层的消息notify到上层APP:

[cpp]  view plain  copy
 print ?
  1. /* Notify manager that new a tag was found */  
  2. e->CallVoidMethod(nat->manager, cached_NfcManager_notifyNdefMessageListeners, tag.get());  
  3. if(e->ExceptionCheck())  
  4. {  
  5.    ALOGE("Exception occurred");  
  6.    kill_client(nat);  
  7. }  

        以其中enableDiscovery()函数为例,说明一下该类的基本操作流程:

[java]  view plain  copy
 print ?
  1. //@paul: native接口,  
  2. private native void doEnableDiscovery(int techMask,  
  3.                                       boolean enableLowPowerPolling,  
  4.                                       boolean enableReaderMode,  
  5.                                       boolean restart);  
  6. @Override  
  7. public void enableDiscovery(NfcDiscoveryParameters params, boolean restart) {  
  8.     doEnableDiscovery(params.getTechMask(), params.shouldEnableLowPowerDiscovery(),params.shouldEnableReaderMode(), restart);  
  9. }  


4.HandoverManager

        此类主要负责NFC到其他传输媒介的跳转,例如Wi-Fi/BT,只是目前AOSP只有是做BT的跳转。Wi-Fi还没有定义Spec,所以还没有这部分的代码。关于BT Handover的spec,可以参考NFC简单介绍中Spec下载章节。


        后续会继续讲解Handover的流程,此部分就不做详细介绍。


5.NfcDispatcher

        此类主要是收到底层Tag消息后,依据tag的类型进行内容解析和数据分发。

[java]  view plain  copy
 print ?
  1. public int dispatchTag(Tag tag) {  
  2.     ...  
  3.       
  4.     //@paul: APP在调用setForegroundDispatch()时,会赋值下列变量  
  5.     synchronized (this) {  
  6.         overrideFilters = mOverrideFilters;  
  7.         overrideIntent = mOverrideIntent;  
  8.         overrideTechLists = mOverrideTechLists;  
  9.         provisioningOnly = mProvisioningOnly;  
  10.     }  
  11.   
  12.     //@paul: 屏幕解锁相关流程  
  13.     boolean screenUnlocked = false;  
  14.     if (!provisioningOnly &&  
  15.             mScreenStateHelper.checkScreenState() == ScreenStateHelper.SCREEN_STATE_ON_LOCKED) {  
  16.         screenUnlocked = handleNfcUnlock(tag);  
  17.         if (!screenUnlocked) {  
  18.             return DISPATCH_FAIL;  
  19.         }  
  20.     }     
  21.     ...  
  22.       
  23.     //@paul: 如果前台Activity启动分发功能,则只需要处理前台分发相关工作即可  
  24.     if (tryOverrides(dispatch, tag, message, overrideIntent, overrideFilters,  
  25.             overrideTechLists)) {  
  26.         return screenUnlocked ? DISPATCH_UNLOCK : DISPATCH_SUCCESS;  
  27.     }  
  28.   
  29.     //@paul: 判断是否为Handover事件  
  30.     if (mHandoverManager.tryHandover(message)) {  
  31.         if (DBG) Log.i(TAG, "matched BT HANDOVER");  
  32.         return screenUnlocked ? DISPATCH_UNLOCK : DISPATCH_SUCCESS;  
  33.     }  
  34.   
  35.     //@paul: 判断是否为Wifi的handover  
  36.     if (NfcWifiProtectedSetup.tryNfcWifiSetup(ndef, mContext)) {  
  37.         if (DBG) Log.i(TAG, "matched NFC WPS TOKEN");  
  38.         return screenUnlocked ? DISPATCH_UNLOCK : DISPATCH_SUCCESS;  
  39.     }  
  40.   
  41.     //@paul: 判断是否为ACTION_NDEF_DISCOVERD  
  42.     if (tryNdef(dispatch, message, provisioningOnly)) {  
  43.         return screenUnlocked ? DISPATCH_UNLOCK : DISPATCH_SUCCESS;  
  44.     }  
  45.     //@paul: 只有在NDEF格式下,才会判断此流程  
  46.     if (screenUnlocked) {  
  47.         // We only allow NDEF-based mimeType matching in case of an unlock  
  48.         return DISPATCH_UNLOCK;  
  49.     }  
  50.     if (provisioningOnly) {  
  51.         // We only allow NDEF-based mimeType matching  
  52.         return DISPATCH_FAIL;  
  53.     }  
  54.   
  55.     //@paul: 判断是否为ACTION_TECH_DISCOVERD  
  56.     if (tryTech(dispatch, tag)) {  
  57.         return DISPATCH_SUCCESS;  
  58.     }  
  59.       
  60.     //@paul: 设置intent为ACTION_TAG_DISCOVERD  
  61.     dispatch.setTagIntent();  
  62.     //@paul: 查询对ACTION_TAG_DISCOVERD感兴趣的activity,并尝试启动  
  63.     if (dispatch.tryStartActivity()) {  
  64.         if (DBG) Log.i(TAG, "matched TAG");  
  65.         return DISPATCH_SUCCESS;  
  66.     }  
  67.   
  68.     if (DBG) Log.i(TAG, "no match");  
  69.     return DISPATCH_FAIL;  
  70. }  

6.P2pLinkManager

        此类主要包含基于LLCP连接的server,构造函数中会创建后续需要的类:

[java]  view plain  copy
 print ?
  1. public P2pLinkManager(Context context, HandoverManager handoverManager, int defaultMiu,int defaultRwSize) {  
  2.     //@paul: 创建NdefPushServer()  
  3.     mNdefPushServer = new NdefPushServer(NDEFPUSH_SAP, mNppCallback);  
  4.     //@paul: 创建SnepServer()  
  5.     mDefaultSnepServer = new SnepServer(mDefaultSnepCallback, defaultMiu, defaultRwSize);  
  6.     //@paul: 创建HandoverServer()  
  7.     mHandoverServer = new HandoverServer(HANDOVER_SAP, handoverManager, mHandoverCallback);  
  8.     //@paul: 创建EchoServer()  
  9.     if (ECHOSERVER_ENABLED) {  
  10.         mEchoServer = new EchoServer();  
  11.     } else {  
  12.         mEchoServer = null;  
  13.     }  
  14.     mPackageManager = context.getPackageManager();  
  15.     mContext = context;  
  16.     //@paul: 创建P2pEventManager()  
  17.     mEventListener = new P2pEventManager(context, this);  
  18.     mHandler = new Handler(this);  
  19.     ...  
  20.  }  


        其中会分别创建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():

[java]  view plain  copy
 print ?
  1. //@paul: 启动SNEP   server  
  2. public void start() {  
  3.     synchronized (SnepServer.this) {  
  4.         if (DBG) Log.d(TAG, "start, thread = " + mServerThread);  
  5.         if (mServerThread == null) {  
  6.             if (DBG) Log.d(TAG, "starting new server thread");  
  7.             mServerThread = new ServerThread();  
  8.             //@paul: ServerThread.run()  
  9.             mServerThread.start();  
  10.             mServerRunning = true;  
  11.         }  
  12.     }  
  13. }  


        其中ServerThread流程如下:

[java]  view plain  copy
 print ?
  1. @Override  
  2. public void run() {  
  3.     ...  
  4.     while (threadRunning) {  
  5.         if (DBG) Log.d(TAG, "about create LLCP service socket");  
  6.         try {  
  7.             synchronized (SnepServer.this) {  
  8.                 //@paul: 创建llcp   服务端socket  
  9.                 //@paul: 包含创建socket,绑定并监听socket  
  10.                 mServerSocket = NfcService.getInstance().createLlcpServerSocket(mServiceSap,  
  11.                         mServiceName, mMiu, mRwSize, 1024);  
  12.             }  
  13.             ...  
  14.             while (threadRunning) {  
  15.                 ...  
  16.                 if (DBG) Log.d(TAG, "about to accept");  
  17.                 //@paul: 阻塞等待客户端连接  
  18.                 //@paul: 一个server  端,可以有多个客户端连接  
  19.                 //@paul: 每次client 端连接都会创建新的thread  
  20.                 LlcpSocket communicationSocket = serverSocket.accept();  
  21.                 if (DBG) Log.d(TAG, "accept returned " + communicationSocket);  
  22.                 if (communicationSocket != null) {  
  23.                     int fragmentLength = (mFragmentLength == -1) ?  
  24.                             mMiu : Math.min(mMiu, mFragmentLength);  
  25.                     //@paul: 一旦有客户端请求连接  
  26.                     new ConnectionThread(communicationSocket, fragmentLength).start();  
  27.                 }  
  28.                 ...  
  29.             }  
  30.             if (DBG) Log.d(TAG, "stop running");  
  31.         } catch (LlcpException e) {  
  32.             Log.e(TAG, "llcp error", e);  
  33.         } catch (IOException e) {  
  34.             Log.e(TAG, "IO error", e);  
  35.         } finally {  
  36.                     ...  
  37.                     try {  
  38.                         mServerSocket.close();  
  39.                     } catch (IOException e) {  
  40.                         // ignore  
  41.                     }  
  42.                     mServerSocket = null;  
  43.                 }  
  44.             }  
  45.         }  
  46.         ...  
  47.     }  
  48. }  

        一旦有client端来连接,就会调用到ConnectionThread的run()函数:

[java]  view plain  copy
 print ?
  1. ConnectionThread(LlcpSocket socket, int fragmentLength) {  
  2.     super(TAG);  
  3.     mSock = socket;  
  4.     //@paul: 创建SnepMessenger 消息处理类  
  5.     mMessager = new SnepMessenger(false, socket, fragmentLength);  
  6. }  
  7.   
  8. @Override  
  9. public void run() {  
  10.     if (DBG) Log.d(TAG, "starting connection thread");  
  11.     try {  
  12.         ...  
  13.         while (running) {  
  14.             //@paul: 每次只要有消息进来,就会进入消息处理流程handleRequest  
  15.             //@paul:后续还会说明handleRequest,此部分不多说明  
  16.             if (!handleRequest(mMessager, mCallback)) {  
  17.                 break;  
  18.             }  
  19.             ...  
  20.         }  
  21.     } catch (IOException e) {  
  22.         ...  
  23.     }  
  24.     ...  
  25. }  

        接下来就是P2pEventManager,此类只要是将底层的消息notify给上层,在其构造函数中,最重要的信息如下:

[java]  view plain  copy
 print ?
  1. public P2pEventManager(Context context, P2pEventListener.Callback callback) {  
  2.     ...  
  3.     final int uiModeType = mContext.getResources().getConfiguration().uiMode  
  4.             & Configuration.UI_MODE_TYPE_MASK;  
  5.     if (uiModeType == Configuration.UI_MODE_TYPE_APPLIANCE) {  
  6.         // "Appliances" don't intrinsically have a way of confirming this, so we  
  7.         // don't use the UI and just autoconfirm where necessary.  
  8.         // Don't instantiate SendUi or else we'll use memory and never reclaim it.  
  9.         mSendUi = null;  
  10.     } else {  
  11.         //@paul: 创建SendUI类,实现与UI层的沟通  
  12.         mSendUi = new SendUi(context, this);  
  13.     }  
  14. }  
        此类中主要实现了以下函数,函数具体信息以后介绍p2p的时候会举例说明:

[java]  view plain  copy
 print ?
  1. public void onP2pInRange()  
  2. public void onP2pNfcTapRequested()  
  3. public void onP2pTimeoutWaitingForLink()  
  4. public void onP2pSendConfirmationRequested()  
  5. public void onP2pSendComplete()  
  6. public void onP2pHandoverNotSupported()  
  7. public void onP2pReceiveComplete(boolean playSound)  
  8. public void onP2pOutOfRange()  
  9. public void onSendConfirmed()  
  10. public void onCanceled()  
  11. public void onP2pSendDebounce()  
  12. public void onP2pResumeSend()  

        前面也有提到,P2pLinkManager中会实例化一个handle,那handler的作用是什么呢?这时候就需要注意到P2pLinkManager实现的方式:

[java]  view plain  copy
 print ?
  1. class P2pLinkManager implements Handler.Callback, P2pEventListener.Callback {  
  2.     ...  
  3. }  

        同时发现代码中出现了handleMessage(),其内容为:

[java]  view plain  copy
 print ?
  1. @Override  
  2. public boolean handleMessage(Message msg) {  
  3.     switch (msg.what) {  
  4.         case MSG_START_ECHOSERVER:  
  5.             ...  
  6.         case MSG_STOP_ECHOSERVER:  
  7.             ...  
  8.         case MSG_WAIT_FOR_LINK_TIMEOUT:  
  9.             ...  
  10.         case MSG_DEBOUNCE_TIMEOUT:  
  11.             ...  
  12.         case MSG_RECEIVE_HANDOVER:  
  13.             ...  
  14.         case MSG_RECEIVE_COMPLETE:  
  15.             ...  
  16.         case MSG_HANDOVER_NOT_SUPPORTED:  
  17.             ...  
  18.         case MSG_SEND_COMPLETE:  
  19.             ...  
  20.     }  
  21.     return true;  
  22. }  

        我们不禁又要问,那这些message都是从哪里传递上来的呢?以MSG_SEND_COMPLETE为例,在P2pLinkManager.java中:

[java]  view plain  copy
 print ?
  1. void onReceiveComplete(NdefMessage msg) {  
  2.     // Make callbacks on UI thread  
  3.     mHandler.obtainMessage(MSG_RECEIVE_COMPLETE, msg).sendToTarget();  
  4. }  


        这样看是底层有确定接收完当前的文件,就会notify给上层(->Framework->App).


7. NfceeAccessControl *

        从代码流程看,只是去读取并解析/etc/nfcee_access.xml文件。此处目前还不是很懂实际的应用场景,先跳过。


8.CardEmulationManager *

        此部分目前还没有详细研究,先跳过。


9.然后呢,然后发现就只有下面这一句了:

[java]  view plain  copy
 print ?
  1. EnableDisableTask().execute(TASK_BOOT)  
       

        那我们看看这个函数做什么了?

[java]  view plain  copy
 print ?
  1. @Override  
  2. protected Void doInBackground(Integer... params) {  
  3.     // Sanity check mState  
  4.     ...  
  5.   
  6.     /* AsyncTask sets this thread to THREAD_PRIORITY_BACKGROUND, 
  7.      * override with the default. THREAD_PRIORITY_BACKGROUND causes 
  8.      * us to service software I2C too slow for firmware download 
  9.      * with the NXP PN544. 
  10.      * TODO: move this to the DAL I2C layer in libnfc-nxp, since this 
  11.      * problem only occurs on I2C platforms using PN544 
  12.      */  
  13.     Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);  
  14.   
  15.     switch (params[0].intValue()) {  
  16.         case TASK_ENABLE:  
  17.             //@paul: 如果传入参数是enable,那就直接初始化NFC芯片等,否则  
  18.             enableInternal();  
  19.             break;  
  20.         case TASK_DISABLE:  
  21.             //@paul: 否则关闭NFC  
  22.             disableInternal();  
  23.             break;  
  24.         case TASK_BOOT:  
  25.             //@paul: 第一次流程上会进入到这里  
  26.             Log.d(TAG, "checking on firmware download");  
  27.             //@paul: 检查prefs中定义的PREF_AIRPLANE_OVERRIDE的值,AOSP没有定义这个值,即为false  
  28.             boolean airplaneOverride = mPrefs.getBoolean(PREF_AIRPLANE_OVERRIDE, false);  
  29.             //@paul:判断prefs中定义的PREF_NFC_ON,AOSP没有定义这个值,即为NFC_ON_DEFAULT  
  30.             //@paul:依据Setting.System中设定,判断mIsAirplaneSensitive(默认true),isAirplaneModeOn(默认false)  
  31.             if (mPrefs.getBoolean(PREF_NFC_ON, NFC_ON_DEFAULT) &&  
  32.                     (!mIsAirplaneSensitive || !isAirplaneModeOn() || airplaneOverride)) {  
  33.                 Log.d(TAG, "NFC is on. Doing normal stuff");  
  34.                 //@paul: 默认NFC打开,开始激活NFC    
  35.                 enableInternal();  
  36.             } else {  
  37.                 Log.d(TAG, "NFC is off.  Checking firmware version");  
  38.                 //@paul: 关闭状态则检查是否要更新fireware  
  39.                 mDeviceHost.checkFirmware();  
  40.             }  
  41.             //@paul: 更新prefs中的PREF_FIRST_BOOT值  
  42.             if (mPrefs.getBoolean(PREF_FIRST_BOOT, true)) {  
  43.                 Log.i(TAG, "First Boot");  
  44.                 mPrefsEditor.putBoolean(PREF_FIRST_BOOT, false);  
  45.                 mPrefsEditor.apply();  
  46.             }  
  47.             break;  
  48.     }  
  49.   
  50.     // Restore default AsyncTask priority  
  51.     Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);  
  52.     return null;  
  53. }  

        一般来说,流程会进入enableInternal()中,你们可能着急了,这里面做什么了呢?
[java]  view plain  copy
 print ?
  1. /** 
  2.  * Enable NFC adapter functions. 
  3.  * Does not toggle preferences. 
  4.  */  
  5. boolean enableInternal() {  
  6.     Log.i(TAG, "Enabling NFC");  
  7.     ...  
  8.       
  9.     try {  
  10.         ...  
  11.         try {  
  12.             //@paul: 执行DH.initialize(),芯片初始化  
  13.             if (!mDeviceHost.initialize()) {  
  14.                 Log.w(TAG, "Error enabling NFC");  
  15.                 updateState(NfcAdapter.STATE_OFF);  
  16.                 return false;  
  17.             }  
  18.         } finally {  
  19.             ...  
  20.         }  
  21.     }   
  22.     ...  
  23.     synchronized (NfcService.this) {  
  24.         ...  
  25.         //@paul: 依据传入值,判断启动对应服务  
  26.         //@paul: mIsNdefPushEnabled由系统设定值确定  
  27.         mP2pLinkManager.enableDisable(mIsNdefPushEnabled, true);  
  28.         updateState(NfcAdapter.STATE_ON);  
  29.     }  
  30.     //@paul: 设置启动,完成,错误时对应的声音文件  
  31.     initSoundPool();  
  32.   
  33.     /* Start polling loop */  
  34.     //@paul: 启动NFC底层轮询  
  35.     applyRouting(true);  
  36.     return true;  
  37. }  


        applyRouting()之后,就启动底层的polling机制,如果底层侦测到有NFC设备靠近,就会进入对应的处理流程。


        到目前为止,基本上NFC的功能都有启动,剩下的工作就是有不同的设备接近的事情,进入不同的流程进行处理。


        后续会从Tag以及P2P两个方面进行系统流程的分析。


        前文提到的CardEmulation 以及NFCEE_ACCESS部分会看后续学习的情况进行补充。

猜你喜欢

转载自blog.csdn.net/u010025003/article/details/72354475
NFC