[NFC]NFC启动流程1

  前面介绍过NFC相关的Spec后,从本章节开始,将进入Android AOSP NFC Frameworks部分的学习。

 

      代码主要的路径存放在:

      Android5.0\packages\apps\Nfc 包含以下目录:

             Assets:含start.png

             etc:nfcee_access实例

             nci:nci规范中的接口和驱动

             nxp:nxp芯片对应的接口和驱动

             res:app用到的图片,字串资源等

             src:主要代码流程

             tests:Google提供的部分测试程序

      Android5.0\packages\apps\Settings\src\com\android\settings\nfc是Setting中关于NFC的代码。

 

      NFC Application的启动不同于Wi-Fi及Wi-Fi P2P等service。

 

      NFC Application对应的AndroidManifest.xml文件中含有关键信息如下:

    <applicationandroid:name=".NfcApplication"
                android:icon="@drawable/icon"
                android:label="@string/app_name"
                 android:theme="@android:style/Theme.Material.Light"
                android:persistent="true"
                android:backupAgent="com.android.nfc.NfcBackupAgent"
                android:killAfterRestore="false"
    >

      

      此处就涉及到android application启动的机制。此处不详细的分析,列举对应的代码,方便大家学习:

     Android5.0\frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java

 public void systemReady(final RunnablegoingCallback) {
          ....
          if (mFactoryTest !=FactoryTest.FACTORY_TEST_LOW_LEVEL) {
                try {
                    List apps =AppGlobals.getPackageManager().
                       getPersistentApplications(STOCK_PM_FLAGS);
                    if (apps != null) {
                        int N = apps.size();
                        int i;
                        for (i=0; i<N; i++){
                            ApplicationInfoinfo
                                =(ApplicationInfo)apps.get(i);
                            if (info != null &&
                                   !info.packageName.equals("android")) {
                               addAppLocked(info, false, null /* ABI override */);
                            }
                        }
                    }
                } catch (RemoteException ex) {
                    // pm is in same process,this will never happen.
                }
         }
          ...
}

 

      继续分析addAppLocked()

final ProcessRecordaddAppLocked(ApplicationInfo info, boolean isolated,
            String abiOverride) {
          ...
        if (app.thread == null &&mPersistentStartingProcesses.indexOf(app) < 0) {
           mPersistentStartingProcesses.add(app);
            startProcessLocked(app, "addedapplication", app.processName, abiOverride,
                    null /* entryPoint */, null /*entryPointArgs */);
        }
          ...
}

 

      最终会call到NfcApplication.java中的NfcApplication()构造函数,其中的onCreate()会被调用到。   

@Override
    public void onCreate() {
        super.onCreate();
        boolean isMainProcess = false;
        // We start a service in a separateprocess to do
        // handover transfer. We don't want toinstantiate an NfcService
        // object in those cases, hence checkthe name of the process
        // to determine whether we're the mainNFC service, or the
        // handover process
        ActivityManager am =(ActivityManager)this.getSystemService(ACTIVITY_SERVICE);
        List processes =am.getRunningAppProcesses();
        Iterator i = processes.iterator();
        while (i.hasNext()) {
            //检查当前运行的App名字是否为"com.android.nfc",如果名字相同,则表示当前启动的程序是主程序
            RunningAppProcessInfo appInfo =(RunningAppProcessInfo)(i.next());
            if (appInfo.pid == Process.myPid()){
               isMainProcess =  (NFC_PROCESS.equals(appInfo.processName));
                break;
            }
        }
        if (UserHandle.myUserId() == 0&& isMainProcess) {</span>
            //启动NfcService
           mNfcService = new NfcService(this);
            HardwareRenderer.enableForegroundTrimming();
        }
    }




      当调用了new NfcService()之后,后面会依次创建各个Service。

 

     在进行后续分析前,简单的列举一下NFC的类图,方便后续的理解:

     上层APP主要透过调用android.nfc.tech及android.nfc的接口来实现期望的功能;而android.nfc.tech和android.nfc透过AIDL的方式调用到NfcService中的接口。Framework中NfcService透过JNI与底层NFC Driver进行沟通,实现发送命令和接收event功能。

 

 

 

 

        在进入NFCService.java前,需要对整个系统的架构有个初步的了解。

 

        DeviceHost.java定义了目前几乎NFC需要的全部interface和API。不同的厂家依据DeviceHost.java提供的interface,实现对应的内容,就可以和上层app进行沟通了。

 

 

 

 

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



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

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

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


1. TagService

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

  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()函数:

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

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

  1. @Override
  2. public synchronized boolean connect(int technology) {
  3. return connectWithStatus(technology) == 0;
  4. }

        看起来还要继续挖:

  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的一个接口:

  1. { "doConnect", "(I)I",
  2. ( void *)com_android_nfc_NativeNfcTag_doConnect},

        继续挖吧:

  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. CONCURRENCY_LOCK();
  7. /* Create the local semaphore */
  8. if (!nfc_cb_data_init(&cb_data, &pRemDevInfo))
  9. {
  10. status = NFCSTATUS_NOT_ENOUGH_MEMORY;
  11. goto clean_and_return;
  12. }
  13. TRACE( "phLibNfc_RemoteDev_Connect(RW)");
  14. REENTRANCE_LOCK();
  15. storedHandle = handle;
  16. status = phLibNfc_RemoteDev_Connect(handle, nfc_jni_connect_callback,( void *)&cb_data);
  17. ......
  18. /* Connect Status */
  19. if(status != NFCSTATUS_SUCCESS)
  20. {
  21. goto clean_and_return;
  22. }
  23. // Success, set poll & act bytes
  24. set_target_pollBytes(e, o, pRemDevInfo);
  25. set_target_activationBytes(e, o, pRemDevInfo);
  26. clean_and_return:
  27. nfc_cb_data_deinit(&cb_data);
  28. CONCURRENCY_UNLOCK();
  29. return status;
  30. }
        好吧,你也不想看了,我也看不到了,最后这些API都是在nxp提供的so中export出来的,目前还看不到源码。


2. NfcAdaptorService

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

  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的一些应用需要在屏灭以及锁屏的情况下也能应用(例如刷公交卡),主要的函数如下:

  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:

  1. static {
  2. System.loadLibrary( "nfc_jni");
  3. }


        进入构造函数后:

  1. public NativeNfcManager(Context context, DeviceHostListener listener) {
  2. mListener = listener;
  3. initializeNativeStructure();
  4. mContext = context;
  5. }

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

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

        继续分析:

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

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

  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()函数为例,说明一下该类的基本操作流程:

  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的类型进行内容解析和数据分发。

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

6.P2pLinkManager

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

  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():

  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流程如下:

  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()函数:

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

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

  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的时候会举例说明:

  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实现的方式:

  1. class P2pLinkManager implements Handler.Callback, P2pEventListener.Callback {
  2. ...
  3. }

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

  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中:

  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.然后呢,然后发现就只有下面这一句了:

EnableDisableTask().execute(TASK_BOOT)
       

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

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

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


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


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


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


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

 

猜你喜欢

转载自blog.csdn.net/weixin_38503885/article/details/80927541
NFC