[Android7.0]开启NFC的流程分析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhulove86/article/details/69666400

在setting设置中开启NFC功能,在NFC开启过程中进行的流程

一、 时序图

在WirelessSettings的设置中进行NFC开启的操作
这里写图片描述

二、代码流程的分析

当设备支持NFC功能的时候。上层应用(如setting应用)通过调用NfcAdapter.java enable()方法来开启和关闭NFC相关的功能。
—NfcAdapter.java

    public boolean enable() {
        try {
            return sService.enable();  //通过binder调用NFCservice中的方法
        } catch (RemoteException e) {
            attemptDeadServiceRecovery(e);
            return false;
        }
    }

在NfcService.java中执行,其中会启动一个异步的task EnableDisableTask来执行enable的动作。
—NfcService.java

        public boolean enable() throws RemoteException {
            NfcPermissions.enforceAdminPermissions(mContext); //进行权限的检查
            saveNfcOnSetting(true); //将当前设定的状态值保存在sp中
            new EnableDisableTask().execute(TASK_ENABLE);
            return true;
        }

在EnableDisableTask是NfcService中的一个内部类,继承自AsyncTask中.在AsyncTask中会先执行doInBackground()方法,由于上一步调用中传入的参数为TASK_ENABLE,所以会执行如下的case

        protected Void doInBackground(Integer... params) {
            // Sanity check mState
            switch (mState) {  //两个在enable和disable过程的中间状态,避免使能过程中重复执行enbale或者disable
                case NfcAdapter.STATE_TURNING_OFF:
                case NfcAdapter.STATE_TURNING_ON:
                    Log.e(TAG, "Processing EnableDisable task " + params[0] + " from bad state " +
                            mState);
                    return null;
            }

            /* 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:  
                    enableInternal();//执行enable的动作
                    break;
                case TASK_DISABLE:
                    disableInternal();//执行diabel的动作
                    break;
                case TASK_BOOT://在NfcService创建的时候,根据当前NFC的状态对NFC模块进行使能,检查固件等操作
                    Log.d(TAG, "checking on firmware download");
                    if (mPrefs.getBoolean(PREF_NFC_ON, NFC_ON_DEFAULT)) {
                        Log.d(TAG, "NFC is on. Doing normal stuff");
                        enableInternal();
                    } else {
                        Log.d(TAG, "NFC is off.  Checking firmware version");
                        mDeviceHost.checkFirmware();
                    }
                    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()方法

        boolean enableInternal() {
            if (mState == NfcAdapter.STATE_ON) {
                return true;
            }
            Log.i(TAG, "Enabling NFC");
            updateState(NfcAdapter.STATE_TURNING_ON); //更新NFC的使能状态

            WatchDogThread watchDog = new WatchDogThread("enableInternal", INIT_WATCHDOG_MS); //创建watchDog线程,检测使能过程是否超时
            watchDog.start();
            try {
                mRoutingWakeLock.acquire();
                try {
                    if (!mDeviceHost.initialize()) {  //对NFC设备进行初始化工作
                        Log.w(TAG, "Error enabling NFC");
                        updateState(NfcAdapter.STATE_OFF);
                        return false;
                    }
                } finally {
                    mRoutingWakeLock.release();
                }
            } finally {
                watchDog.cancel();
            }

            if (mIsHceCapable) {
                // Generate the initial card emulation routing table
                mCardEmulationManager.onNfcEnabled(); //对模拟卡的模块进行enbale的操作
            }

            synchronized (NfcService.this) {
                mObjectMap.clear();
                mP2pLinkManager.enableDisable(mIsNdefPushEnabled, true); //执行P2pLinkManager中的enableDisable(),mIsNdefPushEnabled是否支持进行NdefPush的功能
                updateState(NfcAdapter.STATE_ON);
            }

            initSoundPool(); //初始化NFC提示音(操作过程中对于erro,end等状态进行响铃提示),加载提示音资源文件

            /* Start polling loop */

            applyRouting(true); //启动对于NFC时间的轮询
            return true;
        }

其中 mDeviceHost为NativeNfcManager类的实例化对象,继承自接口类DeviceHost。执行initialize()方法,最终会执行到doInitialize()方法,由于doInitialize()为native 方法,因此最终会通过jni调用到本地native方法中的具体实现,完成对NFC设备的初始化工作。

继续分析P2pLinkManager中的方法enableDisable().该方法完成两个功能,一个是在enable的时候(打开NFC)启动各类相关的服务;另外一个功能就是在disable的时候(关闭NFC)停止各类相关的服务;
具体服务包括SnepServer,NdefPushServer,HandoverServer.其中SnepServer和NdefPushServer主要作用接收来自remote端的NDEF消息。
—P2pLinkManager.java

    public void enableDisable(boolean sendEnable, boolean receiveEnable) {
        synchronized (this) {
            if (!mIsReceiveEnabled && receiveEnable) { //打开NFC功能。
               /*
                  启动mDefaultSnepServer,mNdefPushServer,mHandoverServer服务
                  其中SnepServer,NdefPushServer,HandoverServer这三个类在P2pLinkManager的构造函数中初始化的
               */
                mDefaultSnepServer.start();
                mNdefPushServer.start();
                mHandoverServer.start();
                if (mEchoServer != null) {
                    mHandler.sendEmptyMessage(MSG_START_ECHOSERVER);
                }
            } else if (mIsReceiveEnabled && !receiveEnable) { //关闭NFC功能
                if (DBG) Log.d(TAG, "enableDisable: llcp deactivate");
                onLlcpDeactivated ();
                mDefaultSnepServer.stop();
                mNdefPushServer.stop();
                mHandoverServer.stop();
                if (mEchoServer != null) {
                    mHandler.sendEmptyMessage(MSG_STOP_ECHOSERVER);
                }
            }
            mIsSendEnabled = sendEnable;
            mIsReceiveEnabled = receiveEnable;
        }
    }

进一步分析SnepServer的作用和实现,在SnepServer中包含两个Thread,ServerThread和ConnectionThread.继续分析SnepServer的start()方法
—SnepServer.java

  public void start() {
  synchronized (SnepServer.this) {
  if (mServerThread == null) {
  mServerThread = new ServerThread();
  mServerThread.start();
  mServerRunning = true;
  }
  }
  }

在ServerThread的run()方法中,主要做两件事,创建serverSocket,并进行监听;在接收到监听之后重新开启ConnectionThread线程。

     class ServerThread extends Thread {
        private boolean mThreadRunning = true;
        LlcpServerSocket mServerSocket;

        @Override
        public void run() {
            boolean threadRunning;
            synchronized (SnepServer.this) {
                threadRunning = mThreadRunning;
            }

            while (threadRunning) {
                try {
                    synchronized (SnepServer.this) {
                       //创建LlcpServerSocket,其中mServiceSap:端口值为4 ,mServiceName:server名称urn:nfc:sn:snep
                       //mMiu和mRwSize为本地LLC的Miu和Rw的大小,1024为线性缓冲的大小,最终会根据这四个参数在native中创建buffer
                       /*
                            sWorkingBuffer.buffer = (uint8_t*)malloc((miu*rw)+miu+linearBufferLength);
                             sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength;
                        */

                        mServerSocket = NfcService.getInstance().createLlcpServerSocket(mServiceSap,
                                mServiceName, mMiu, mRwSize, 1024);
                    }
                    if (mServerSocket == null) {
                        if (DBG) Log.d(TAG, "failed to create LLCP service socket");
                        return;
                    }
                    if (DBG) Log.d(TAG, "created LLCP service socket");
                    synchronized (SnepServer.this) {
                        threadRunning = mThreadRunning;
                    }

                    while (threadRunning) {
                        LlcpServerSocket serverSocket;
                        synchronized (SnepServer.this) {
                            serverSocket = mServerSocket;
                        }

                        if (serverSocket == null) {
                            if (DBG) Log.d(TAG, "Server socket shut down.");
                            return;
                        }
                        if (DBG) Log.d(TAG, "about to accept");
                        //监听socket通讯,获取incoming请求的socket,具体可以参考一下native中的实现,此处为阻塞的函数调用。直到有incoming请求
                        LlcpSocket communicationSocket = serverSocket.accept();
                        if (DBG) Log.d(TAG, "accept returned " + communicationSocket);
                        if (communicationSocket != null) {
                            int fragmentLength = (mFragmentLength == -1) ?
                                    mMiu : Math.min(mMiu, mFragmentLength);
                            new ConnectionThread(communicationSocket, fragmentLength).start(); //另起ConnectionThread,在其中进行socket的操作
                        }

                        synchronized (SnepServer.this) {
                            threadRunning = mThreadRunning;
                        }
                    }
                    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 {
                    synchronized (SnepServer.this) {
                        if (mServerSocket != null) {
                            if (DBG) Log.d(TAG, "about to close");
                            try {
                                mServerSocket.close();
                            } catch (IOException e) {
                                // ignore
                            }
                            mServerSocket = null;
                        }
                    }
                }

                synchronized (SnepServer.this) {
                    threadRunning = mThreadRunning;
                }
            }
        }

        public void shutdown() {
           ....
            }
        }
    }

ConnectionThread也是SnepServer中的内部类,在该类中主要通过ServerThread中accept得到的socket来接收数据。

   private class ConnectionThread extends Thread {
        private final LlcpSocket mSock;
        private final SnepMessenger mMessager;

        ConnectionThread(LlcpSocket socket, int fragmentLength) {
            super(TAG);
            mSock = socket;
            mMessager = new SnepMessenger(false, socket, fragmentLength);
        }

        @Override
        public void run() {
            if (DBG) Log.d(TAG, "starting connection thread");
            try {
                boolean running;
                synchronized (SnepServer.this) {
                    running = mServerRunning;
                }

                while (running) {
                    if (!handleRequest(mMessager, mCallback)) {  //在handleRequest()中进行socket get和put的操作,最终在SnepMessenger中进行处理  
                        break;
                    }

                    synchronized (SnepServer.this) {
                        running = mServerRunning;
                    }
                }
            } catch (IOException e) {
                if (DBG) Log.e(TAG, "Closing from IOException");
            } finally {
                try {
                    if (DBG) Log.d(TAG, "about to close");
                    mSock.close();
                } catch (IOException e) {
                    // ignore
                }
            }

            if (DBG) Log.d(TAG, "finished connection thread");
        }
    }

到此P2pLinkManager中的任务已经完成,回到NfcService中继续分析enableInternal()方法。在enableInternal()中会执行initSoundPool和applyRouting。重点分析一下applyRouting()方法,开始扫描tag和p2p事件
—NfcService.java

    void applyRouting(boolean force) {
        synchronized (this) {
            if (!isNfcEnabledOrShuttingDown()) {
                return;
            }
            WatchDogThread watchDog = new WatchDogThread("applyRouting", ROUTING_WATCHDOG_MS); //创建WatchDog,检测是否在超时
            if (mInProvisionMode) {
                mInProvisionMode = Settings.Secure.getInt(mContentResolver,
                        Settings.Global.DEVICE_PROVISIONED, 0) == 0;
                if (!mInProvisionMode) {
                    // Notify dispatcher it's fine to dispatch to any package now
                    // and allow handover transfers.
                    mNfcDispatcher.disableProvisioningMode();
                }
            }
            // Special case: if we're transitioning to unlocked state while
            // still talking to a tag, postpone re-configuration.
            if (mScreenState == ScreenStateHelper.SCREEN_STATE_ON_UNLOCKED && isTagPresent()) {
                Log.d(TAG, "Not updating discovery parameters, tag connected.");
                mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_RESUME_POLLING),
                        APPLY_ROUTING_RETRY_TIMEOUT_MS);
                return;
            }

            try {
                watchDog.start();
                // Compute new polling parameters
                NfcDiscoveryParameters newParams = computeDiscoveryParameters(mScreenState);
               /*
                给底层设定扫描的参数,包括Tech,以及各种lowPowr,readMode,P2P等使能
               */
                if (force || !newParams.equals(mCurrentDiscoveryParameters)) {
                    if (newParams.shouldEnableDiscovery()) {
                        boolean shouldRestart = mCurrentDiscoveryParameters.shouldEnableDiscovery();
                        mDeviceHost.enableDiscovery(newParams, shouldRestart);  //给native具体实现中设定参数
                    } else {
                        mDeviceHost.disableDiscovery();
                    }
                    mCurrentDiscoveryParameters = newParams;
                } else {
                    Log.d(TAG, "Discovery configuration equal, not updating.");
                }
            } finally {
                watchDog.cancel();
            }
        }
    }

到此为止完成了NFC开启的过程。


后续会继续更新NFC协议,以及NFC其他核心类,以及传输相关的内容。

猜你喜欢

转载自blog.csdn.net/zhulove86/article/details/69666400