NFC源码分析之R/W工作模式

时间:2024-04-12 21:22:32
文章整理总结java层,NFC读取和写入Tag的流程。
整体的时序图:
NFC源码分析之R/W工作模式
1、读取Tag的流程
    NfcService启动完成后,会通过NfcService中的applyRouting方法设置对应的Discovery,也就是NCI的
2103的命令(此处不了解不影响后面),根据设置的命令参数来决定设备是处于listen模式,还是polling模式。
当处于polling模式下会检测那个Tag进入到了自己的射频厂,进而产生反应。与其相对的是listen模式,Tag
就相当于是listen模式,监听谁往外polling,产生响应.
下面先详细分析applyRouting。
参数force为true的时候,基本上就会执行一次enableDiscovery.
1
void applyRouting(boolean force) {
2
    synchronized (this) {
3
        ......
4
        //mInProvisionMode:用来标记当前系统是否处于开机向导界面.
5
        //对应于android开机时候的引导provision apk,是否出在引导模式
6
        if (mInProvisionMode) {
7
            mInProvisionMode = Settings.Secure.getInt(mContentResolver,
8
                    Settings.Global.DEVICE_PROVISIONED, 0) == 0;
9
            //当运行到这里的时候就代表,这是刷完系统,开机引导完,第一次走到这里,
10
            //并且现在开机引导已经完毕,此时下面可能已经是false
11
            if (!mInProvisionMode) {
12
                //就是设置NfcDispatcher中的mProvisioningOnly = false;
13
                mNfcDispatcher.disableProvisioningMode();
14
                //调用native方法doSetProvisionMode,去通知native层,当前不是处于ProvisionMode
15
                mDeviceHost.doSetProvisionMode(mInProvisionMode);
16
            }
17
        }
18
        // 当此时正在和一个Tag在通信的时候,延迟re-configuration.
19
        if (mScreenState == ScreenStateHelper.SCREEN_STATE_ON_UNLOCKED && isTagPresent()) {
20
            Log.d(TAG, "Not updating discovery parameters, tag connected.");
21
            mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_RESUME_POLLING),
22
                    APPLY_ROUTING_RETRY_TIMEOUT_MS);
23
            return;
24
        }
25
        try {
26
            //此处更新于NFC RF的Discovery参数.
27
            NfcDiscoveryParameters newParams = computeDiscoveryParameters(mScreenState);
28
            //传入参数为true的时候或者参数有所变化.
29
            if (force || !newParams.equals(mCurrentDiscoveryParameters)) {
30
                //只要routingtable变过,或者有新的tech的改变。
31
                if (newParams.shouldEnableDiscovery()) {
32
                    boolean shouldRestart = 
33
                               mCurrentDiscoveryParameters.shouldEnableDiscovery();
34
                    //最重要的就是调用到了这里,mDeviceHost的实现类是NativeNfcManager
35
                    //最终调用到内部的如下:
36
                    // private native void doEnableDiscovery(int techMask,
37
                    //                  boolean enableLowPowerPolling,
38
                    //                  boolean enableReaderMode,
39
                    //                  boolean enableP2p,
40
                    //                  boolean restart);
41
                    //去native层,初始化RF的相关参数。
42
                    mDeviceHost.enableDiscovery(newParams, shouldRestart);
43
                } else {
44
                    mDeviceHost.disableDiscovery();
45
                }
46
                mCurrentDiscoveryParameters = newParams;
47
            } else {
48
                Log.d(TAG, "Discovery configuration equal, not updating.");
49
            }
50
        } finally {
51
            ......
52
        }
53
    }
54
}
        我们看一下computeDiscoveryParameters这个函数,它返回NfcDiscoveryParameters,这个类描述了
用于enable NFC的tag discovery、polling、host card emulation的各个参数,配置的不同最终初始化的NFC
功能不同.
1
//基于屏幕的状态重新计算NfcDiscoveryParameters.
2
private NfcDiscoveryParameters computeDiscoveryParameters(int screenState) {
3
    NfcDiscoveryParameters.Builder paramsBuilder = NfcDiscoveryParameters.newBuilder();
4
    //当屏幕状态>= NFC_POLLING_MODE,而如下:
5
    //static final int NFC_POLLING_MODE = ScreenStateHelper.SCREEN_STATE_ON_UNLOCKED;
6
    //其实就是在亮屏并且处于解锁状态的时候,或mIsTaskBoot为true,mIsTaskBoot这个变量只有在处于初始化
7
    //阶段,NfcService从构造的结尾处进行Nfc的启动.
8
    // Polling;mIsInterruptedByCamera :是否被camera打断.
9
    if (((screenState >= NFC_POLLING_MODE)||mIsTaskBoot) && !mIsInterruptedByCamera) {
10
        //mReaderModeParams是在setReaderMode()这个接口中被设置的,应该是第三方app,在它们
11
        //的应用界面想要把手机作为reader的时候会打印。
12
        //当前NFC读模式开启后,按照协议,看看当前的Tag属于那种类型的Tag,然后设置techMask.
13
        if (mReaderModeParams != null) {
14
            int techMask = 0;
15
            if ((mReaderModeParams.flags & NfcAdapter.FLAG_READER_NFC_A) != 0)
16
                techMask |= NFC_POLL_A;
17
            if ((mReaderModeParams.flags & NfcAdapter.FLAG_READER_NFC_B) != 0)
18
                techMask |= NFC_POLL_B;
19
            if ((mReaderModeParams.flags & NfcAdapter.FLAG_READER_NFC_F) != 0)
20
                techMask |= NFC_POLL_F;
21
            if ((mReaderModeParams.flags & NfcAdapter.FLAG_READER_NFC_V) != 0)
22
                techMask |= NFC_POLL_ISO15693;
23
            if ((mReaderModeParams.flags & NfcAdapter.FLAG_READER_NFC_BARCODE) != 0)
24
                techMask |= NFC_POLL_KOVIO;
25
            paramsBuilder.setTechMask(techMask);
26
            paramsBuilder.setEnableReaderMode(true);
27
        } else {
28
            //系统内部的会设置为NFC_POLL_DEFAULT这个参数 对应:
29
            //static final int NFC_POLL_DEFAULT = -1; 但是感觉传入到native层的时候,可能根据这个
30
            //有个默认的设置.
31
            paramsBuilder.setTechMask(NfcDiscoveryParameters.NFC_POLL_DEFAULT);
32
            paramsBuilder.setEnableP2p(true);
33
        }
34
    //锁屏并且在ProvisionMode
35
    } else if (screenState == ScreenStateHelper.SCREEN_STATE_ON_LOCKED && mInProvisionMode) {
36
        paramsBuilder.setTechMask(NfcDiscoveryParameters.NFC_POLL_DEFAULT);
37
        paramsBuilder.setEnableP2p(true);
38
    //当有人调用addNfcUnlockHandler的时候,isLockscreenPollingEnabled才可能被设置为true,
39
    //发现在sony的设计中LockScreenHeadsetHandover的构造处有添加.
40
    //注意此时的屏幕状态是SCREEN_STATE_ON_LOCKED.就是亮屏,但是锁着那!
41
    } else if (screenState == ScreenStateHelper.SCREEN_STATE_ON_LOCKED &&
42
            mNfcUnlockManager.isLockscreenPollingEnabled()) {
43
        // For lock-screen tags, no low-power polling
44
        paramsBuilder.setTechMask(mNfcUnlockManager.getLockscreenPollMask());
45
        paramsBuilder.setEnableLowPowerDiscovery(false);
46
        paramsBuilder.setEnableP2p(false);
47
    }
48
    //mIsHceCapable代表是否具有卡模拟的功能。不插卡的时候也是true,可能是针对HCE的?
49
    if (mIsHceCapable && mScreenState >= ScreenStateHelper.SCREEN_STATE_ON_LOCKED) {
50
        // Host routing is always enabled at lock screen or later
51
        paramsBuilder.setEnableHostRouting(true);
52
    }
53
    //只要commit过routingtable,或者设置过屏幕状态,或者换过卡,等等mIsRoutingTableDirty会为true.
54
    if(mIsRoutingTableDirty) {
55
        mIsRoutingTableDirty = false;
56
        int protoRoute = mNxpPrefs.getInt("PREF_MIFARE_DESFIRE_PROTO_ROUTE_ID", 
57
                                 GetDefaultMifareDesfireRouteEntry());
58
        int defaultRoute=mNxpPrefs.getInt("PREF_SET_DEFAULT_ROUTE_ID", 
59
                                          GetDefaultRouteEntry());
60
        int techRoute=mNxpPrefs.getInt("PREF_MIFARE_CLT_ROUTE_ID", 
61
                                       GetDefaultMifateCLTRouteEntry());
62
        defaultRoute = NfcCertDebugModeUtil.calculateDefaultRoute(defaultRoute,
63
                mDeviceHost.getDefaultAidPowerState(), ROUTE_LOC_MASK);
64
        if (DBG) Log.d(TAG, "Set default Route Entry");
65
        setDefaultRoute(defaultRoute, protoRoute, techRoute);
66
    }
67
    ...
68
    return paramsBuilder.build(); //返回对应字符串,代表相关的参数
69
}
       以上是关于NFC工作的RF状态的描述分析,下面开始分析,当NFC检测到remote tag的时候的回调。
最终native层通过NativeNfcManager.cpp中的
1
gCachedNfcManagerNotifyNdefMessageListeners = e->GetMethodID(cls.get(),
2
        "notifyNdefMessageListeners", "(Lcom/android/nfc/dhimpl/NativeNfcTag;)V");
回调于NfcTag.cpp中的createNativeNfcTag(..)方法,然后通过JNI调用到NativeNfcManager.java中的
1
private void notifyNdefMessageListeners(NativeNfcTag tag) {
2
    mListener.onRemoteEndpointDiscovered(tag);
3
}
mListener的实现就是NfcService,又重新回到Nfcservice中
1
@Override
2
public void onRemoteEndpointDiscovered(TagEndpoint tag) {
3
    sendMessage(NfcService.MSG_NDEF_TAG, tag);
4
}
5
void sendMessage(int what, Object obj) {
6
    Message msg = mHandler.obtainMessage();
7
    msg.what = what;
8
    msg.obj = obj;
9
    mHandler.sendMessage(msg);
10
}
       到此为止,native层对发现的tag进行了一系列的初始化和封装操作,就是按照ndef协议把Tag的消息封
到TagEndpoint当中,TagEndpoint就是代表了一个远端的Nfc tag.
      然后执行到mHandler中的MSG_NDEF_TAG
1
    case MSG_NDEF_TAG:
2
        if (DBG) Log.d(TAG, "Tag detected, notifying applications");
3
        ......
4
        //当有别人调用setReaderMode()接口去设置mReaderModeParams的时候.
5
        //如第三方app模拟reader.(一般都是在第三方app的reader/write界面,由它们调用)
6
        synchronized (NfcService.this) {
7
            readerParams = mReaderModeParams;
8
        }
9
        if (readerParams != null) {
10
            presenceCheckDelay = readerParams.presenceCheckDelay;
11
            //如果FLAG_READER_SKIP_NDEF_CHECK标记位不为0,那么直接开始调用dispatchTagEndpoint分发
12
            if ((readerParams.flags & NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK) != 0) {
13
                if (DBG) Log.d(TAG, "Skipping NDEF detection in reader mode");
14
                tag.startPresenceChecking(presenceCheckDelay, callback);
15
                dispatchTagEndpoint(tag, readerParams);
16
                break;
17
            }
18
        }
19
        //当是NFC Barcode的时候也是直接分发,看其实意思是解析NFC条形码的时候
20
        if (tag.getConnectedTechnology() == TagTechnology.NFC_BARCODE) {
21
            ......
22
            if (DBG) Log.d(TAG, "Skipping NDEF detection for NFC Barcode");
23
            tag.startPresenceChecking(presenceCheckDelay, callback);
24
            dispatchTagEndpoint(tag, readerParams);
25
            break;
26
        }
27
        //去调用NativeNfcTag的findAndReadNdef,进行相关初始化后把native层的数据按照NDEF
28
        //协议封装成java中的类NdefMessage.(此时就是读取NDEF格式的信息了)
29
        NdefMessage ndefMsg = tag.findAndReadNdef();
30
        //解析的消息无法被实例化成NDEF的时候。
31
        if (ndefMsg == null) {
32
            // First try to see if this was a bad tag read
33
            if (!tag.reconnect()) {
34
                tag.disconnect();
35
                //当是亮屏的时候弹出提示信息.
36
                if (mScreenState == ScreenStateHelper.SCREEN_STATE_ON_UNLOCKED) {
37
                    //"Read error. Try again"
38
                    String toastString = mContext.getString(
39
                            R.string.nfc_strings_toast_prompt_touch_again_txt);
40
                    if (!ToastMaster.isSameToastShown(toastString)) {
41
                        ToastMaster.showToast(mContext, toastString);
42
                    }
43
                }
44
                break;
45
            }
46
        }
47
        //这个如名字是抖动的tag,就是由于距离没控制好,一直检测到同一个tag的时候。
48
        //应该就是这个Tag检测完,没有离开范围,就不会再次检测
49
        if (debounceTagUid != null) {
50
            // If we're debouncing and the UID or the NDEF message of the tag match,
51
            // don't dispatch but drop it.
52
            ......
53
        }
54
        mLastReadNdefMessage = ndefMsg;
55
        tag.startPresenceChecking(presenceCheckDelay, callback);
56
        //解析出问题的ndef消息也要分发出去.
57
        dispatchTagEndpoint(tag, readerParams);
58
        break;
59
        //case  MSG_NDEF_TAG over.
       至此开始准备进行读取Tag。
      findAndReadNdef的解析,位于NativeNfcTag.这个方法中的注释为我们的分析带来很多遍历,此处需要
特别注意:NativeNfcTag是Nfc Tag在java层的一个代表,它在native层由NfcTag对象来表示,在NfcTag.cpp
有如下方法用于创建NativeNfcTag对象,并且是实例化相应的参数,注释写的很详细,源码如下:
1
/*******************************************************************************
2
**
3
** Function:        createNativeNfcTag
4
**
5
** Description:    Create a brand new Java NativeNfcTag object;
6
**                  fill the objects's member variables with data;
7
**                  notify NFC service;
8
**                  activationData: data from activation.
9
**
10
** Returns:        None
11
**
12
*******************************************************************************/
13
void NfcTag::createNativeNfcTag (tNFA_ACTIVATED& activationData)
14
{
15
    static const char fn [] = "NfcTag::createNativeNfcTag";
16
    ALOGV("%s: enter", fn);
17
18
    JNIEnv* e = NULL;
19
    ScopedAttach attach(mNativeData->vm, &e);
20
    if (e == NULL)
21
    {
22
        ALOGE("%s: jni env is null", fn);
23
        return;
24
    }
25
26
    ScopedLocalRef<jclass> tag_cls(e, e->GetObjectClass(mNativeData->cached_NfcTag));
27
    if (e->ExceptionCheck())
28
    {
29
        e->ExceptionClear();
30
        ALOGE("%s: failed to get class", fn);
31
        return;
32
    }
33
34
    //create a new Java NativeNfcTag object
35
    jmethodID ctor = e->GetMethodID(tag_cls.get(), "<init>", "()V");
36
    ScopedLocalRef<jobject> tag(e, e->NewObject(tag_cls.get(), ctor));
37
38
    //fill NativeNfcTag's mProtocols, mTechList, mTechHandles, mTechLibNfcTypes
39
    fillNativeNfcTagMembers1(e, tag_cls.get(), tag.get());
40
41
    //fill NativeNfcTag's members: mHandle, mConnectedTechnology
42
    fillNativeNfcTagMembers2(e, tag_cls.get(), tag.get(), activationData);
43
44
    //fill NativeNfcTag's members: mTechPollBytes
45
    fillNativeNfcTagMembers3(e, tag_cls.get(), tag.get(), activationData);
46
47
    //fill NativeNfcTag's members: mTechActBytes
48
    fillNativeNfcTagMembers4(e, tag_cls.get(), tag.get(), activationData);
49
50
    //fill NativeNfcTag's members: mUid
51
    fillNativeNfcTagMembers5(e, tag_cls.get(), tag.get(), activationData);
52
53
    if (mNativeData->tag != NULL)
54
    {
55
        e->DeleteGlobalRef(mNativeData->tag);
56
    }
57
    mNativeData->tag = e->NewGlobalRef(tag.get());
58
59
    ALOGV("%s; mNumDiscNtf=%x", fn,mNumDiscNtf);
60
    if(!mNumDiscNtf || NfcTag::getInstance().checkNextValidProtocol() == -1)
61
    {
62
        //notify NFC service about this new tag
63
        mNumDiscNtf = 0;
64
        ALOGV("%s: try notify nfc service", fn);
65
        storeActivationParams();
66
        e->CallVoidMethod(mNativeData->manager, 
67
                          android::gCachedNfcManagerNotifyNdefMessageListeners, tag.get());
68
        if (e->ExceptionCheck())
69
        {
70
            e->ExceptionClear();
71
            ALOGE("%s: fail notify nfc service", fn);
72
        }
73
        deleteglobaldata(e);
74
    }
75
    else
76
    {
77
        ALOGV("%s: Selecting next tag", fn);
78
    }
79
80
    ALOGV("%s: exit", fn);
81
}
    如上需要注意,每次检测到一个Tag都会调用createNativeNfcTag,去实例化一个native对应的对象(刷一
次卡创建一个),然后实例化各个变量。也因此如下变量:
1
// mConnectedHandle stores the *real* libnfc handle
2
// that we're connected to.
3
private int mConnectedHandle;
     每次都是0,因为是默认值嘛!而且在native层也没有对它进行初始化。至于NativeNfcTag这个类的销
毁,好像出了这个方法就销毁了(native层)?Java层在相应的方法中使用完毕以后也就释放了
     下面以findAndReadNdef为切入点,结合注释看一下connect和read Tag的流程.
1
@Override
2
public NdefMessage findAndReadNdef(){
3
    //去获取当前Tag支持的所有的tech
4
    //如下technologies、handles都是在native层就实例化好的.
5
    //TagTechnology有很多种, NFC_A、NFC_B、ISO_DEP、NFC_F、NFC_V.
6
    //关于technologies和handles也需要多说一下,暂时对这块认知不高,通过Log观察到如下:
7
    //使用了四张平常的卡进行测试抓取, 每次technologies和数量和handles的数量都是一致的,
8
    //technologies是卡片支持的协议,对应于TagTechnology.java中的成员变量.
9
    //handles 在这次试验的手机上值都是1,无论size是对少,每个位置都是1,而handles的添加在java层
10
    //都是对应这个变量 private int mConnectedHandle;前面有注释是说代表了libnfc的handle,那么
11
    //感觉一般的平台肯定是用的一个libnfc库呀,难道有些会用两个libnfc?然后去进行选择?
12
    int[] technologies = getTechList();
13
    int[] handles = mTechHandles;
14
    NdefMessage ndefMsg = null;
15
    boolean foundFormattable = false;
16
    int formattableHandle = 0;
17
    int formattableLibNfcType = 0;
18
    int status;
19
    for (int techIndex = 0; techIndex < technologies.length; techIndex++) {
20
        for (int i = 0; i < techIndex; i++) {
21
            //高效处理,我们目前handle都是一样的情况
22
            if (handles[i] == handles[techIndex]) {
23
                continue;  // don't check duplicate handles
24
            }
25
        }
26
        //网上说明:判断connectedHandle与当前Index对应的handle的关系,并更新状态,。
27
        //自己理解不深,源码见后面.
28
        status = connectWithStatus(technologies[techIndex]);
29
        //连接失败直接跳过本次循环,连接下一个Tech!!
30
        if (status != 0) {
31
            Log.d(TAG, "Connect Failed - status = "+ status);
32
            if (status == STATUS_CODE_TARGET_LOST) {
33
                break;
34
            }
35
            continue;  // try next handle
36
        }
37
        if (!foundFormattable) {
38
            //如果是标准的Ndef格式,进行如下操作,自己测试的四个卡都是.
39
            if (isNdefFormatable()) {
40
                foundFormattable = true;
41
                formattableHandle = getConnectedHandle();
42
                formattableLibNfcType = getConnectedLibNfcType();
43
            }
44
            //再次connect
45
            reconnect();
46
        }
47
48
        int[] ndefinfo = new int[2];
49
        //检查当前tag中ndef数据的合法性,传入ndefinfo会走到native层,进行数据的赋值.
50
        status = checkNdefWithStatus(ndefinfo);
51
        if (status != 0) {
52
            Log.d(TAG, "Check NDEF Failed - status = " + status);
53
            if (status == STATUS_CODE_TARGET_LOST) {
54
                break;
55
            }
56
            continue;  // try next handle
57
        }
58
        // found our NDEF handle
59
        boolean generateEmptyNdef = false;
60
        //check完以后ndefinfo这个里面的数据,正常情况下就是完整的了。
61
        int supportedNdefLength = ndefinfo[0];
62
        int cardState = ndefinfo[1];
63
        //此处才是真正的读取,读取tag中的数据,读出来的是字节数组。
64
        //注意此处经常丢失Log
65
        byte[] buff = readNdef();
66
        if (buff != null && buff.length > 0) {
67
            try {
68
                //正常的应该走到这里,通过获取的数据实例化NdefMessage.
69
                //在NdefMessage实例化的时候就按照NDEF的协议去解析这个byte数组
70
                //中的数据,然后封装成各个类和相应的字段供我们到时候直接调用
71
                ndefMsg = new NdefMessage(buff);
72
                //把检测到的数据都保存起来.
73
                addNdefTechnology(ndefMsg,
74
                        getConnectedHandle(),
75
                        getConnectedLibNfcType(),
76
                        getConnectedTechnology(),
77
                        supportedNdefLength, cardState);
78
                foundFormattable = false;
79
                //最后又进行了一次连接,不知道有何作用
80
                reconnect();
81
            } catch (FormatException e) {
82
              // Create an intent anyway, without NDEF messages
83
              generateEmptyNdef = true;
84
            }
85
        } else if(buff != null){
86
            // Empty buffer, unformatted tags fall into this case
87
            generateEmptyNdef = true;
88
        }
89
        //当产生异常的时候generateEmptyNdef为true的一些处理
90
        if (generateEmptyNdef) {
91
            ndefMsg = null;
92
            //存一个空NdefMessage
93
            addNdefTechnology(null,
94
                  getConnectedHandle(),
95
                  getConnectedLibNfcType(),
96
                  getConnectedTechnology(),
97
                  supportedNdefLength, cardState);
98
            foundFormattable = false;
99
            reconnect();
100
        }
101
        break;
102
    }
103
    ......
104
    return ndefMsg;
105
}
       connectWithStatus源码:(注释挺多的,容易看懂但不容易理解)
1
private native int doConnect(int handle);
2
public synchronized int connectWithStatus(int technology) {
3
    ......
4
    int status = -1;
5
    for (int i = 0; i < mTechList.length; i++) {
6
        //循环遍历所有的tech,找到需要connect的tech
7
        if (mTechList[i] == technology) {
8
            //当前的tag被检测到,第一次走到这里的时候mConnectedHandle是默认值,
9
            //因为没有在native层进行实例化,所以是mConnectedHandle = 0;
10
            // Get the handle and connect, if not already connected
11
            if (mConnectedHandle != mTechHandles[i]) {
12
                // We're not yet connected to this handle, there are
13
                // a few scenario's here:
14
                // 1) We are not connected to anything yet - allow
15
                // 2) We are connected to a technology which has
16
                //    a different handle (multi-protocol tag); we support
17
                //    switching to that.
18
                if (mConnectedHandle == -1) { 
19
                    //这个情况,Log一直观察不到,无论是重启/刷机的第一次,还是平常都不行
20
                    //感觉也正常,因为可能是libnfc只要连接上,就不会初始化成-1.
21
                    // Not connected yet
22
                    //status = doConnect(mTechHandles[i]);
23
                    Log.d(TAG," readerParams doConnect");
24
                    status = doConnect(i);
25
                } else {
26
                    //调用reconnectWithStatus传入handle.(暂时发现每个tag的handle都是一样的)
27
                    // Connect to a tech with a different handle
28
                    Log.d(TAG," readerParams Connect to a tech with a different handle");
29
                    status = reconnectWithStatus(i);
30
                }
31
                //如果成功链接,mConnectedHandle都是1(在我这个测试手机上),按照前面的变量分析的话,
32
                //也可以理解
33
                if (status == 0) {
34
                    mConnectedHandle = mTechHandles[i];
35
                    mConnectedTechIndex = i;(把tech所在的正确的index传入)
36
                }
37
            } else {
38
                //按照目前的手机和Log和Tag的分析都没有走到这里,暂时不太理解
39
                // 1) We are connected to a technology which has the same
40
                //    handle; we do not support connecting at a different
41
                //    level (libnfc auto-activates to the max level on
42
                //    any handle).
43
                // 2) We are connecting to the ndef technology - always
44
                //    allowed.
45
                if ((technology == TagTechnology.NDEF) ||
46
                        (technology == TagTechnology.NDEF_FORMATABLE)) {
47
                    // special case for NDEF, this will cause switch to ISO_DEP frame intf
48
                    i = 0;
49
                  // status = 0;
50
                }
51
                status = reconnectWithStatus(i);
52
                ......
53
54
                if (status == 0) {
55
                    mConnectedTechIndex = i;
56
                    // Handle was already identical
57
                }
58
            }
59
            break;
60
        }
61
    }
62
    ......
63
    return status;
64
}
       reconnectWithStatus()的相关源码流程:
1
native int doHandleReconnect(int handle);
2
public synchronized int reconnectWithStatus(int handle) {
3
    ......
4
    //最后就是调用到native的方法去做进一步的连接操作.
5
    int status = doHandleReconnect(handle);
6
    ......
7
    return status;
8
}
        reconnect相关源码分析.
1
@Override
2
public synchronized boolean reconnect() {
3
    return reconnectWithStatus() == 0;
4
}
5
native int doReconnect();
6
public synchronized int reconnectWithStatus() {
7
    ......
8
    int status = doReconnect();
9
    ......
10
    return status;
11
}
        checkNdefWithStatus相关源码分析
1
private native int doCheckNdef(int[] ndefinfo);
2
private synchronized int checkNdefWithStatus(int[] ndefinfo) {
3
    ......
4
    int status = doCheckNdef(ndefinfo);
5
    ......
6
    return status;
7
}
      addNdefTechnology相关源码
1
public void addNdefTechnology(NdefMessage msg, int handle, int libnfcType,
2
        int javaType, int maxLength, int cardState) {
3
    synchronized (this) {
4
        addTechnology(TagTechnology.NDEF, handle, libnfcType);
5
6
        Bundle extras = new Bundle();
7
        extras.putParcelable(Ndef.EXTRA_NDEF_MSG, msg);
8
        extras.putInt(Ndef.EXTRA_NDEF_MAXLENGTH, maxLength);
9
        extras.putInt(Ndef.EXTRA_NDEF_CARDSTATE, cardState);
10
        extras.putInt(Ndef.EXTRA_NDEF_TYPE, getNdefType(libnfcType, javaType));
11
        Log.d(TAG,"addNdefTechnology  readerParams mTechExtras = "+mTechExtras);
12
        //getTechExtras内部会更具Tech,创建出一个Bundle,最终NfcService可以获取这个然后取出
13
        //来其中的数据,以及重要的NdefMessage.
14
        if (mTechExtras == null) {
15
            // This will build the tech extra's for the first time,
16
            // including a NULL ref for the NDEF tech we generated above.
17
            Bundle[] builtTechExtras = getTechExtras();
18
            builtTechExtras[builtTechExtras.length - 1] = extras;
19
        }
20
        else {
21
            // Tech extras were built before, patch the NDEF one in
22
            Bundle[] oldTechExtras = getTechExtras();
23
            Bundle[] newTechExtras = new Bundle[oldTechExtras.length + 1];
24
            System.arraycopy(oldTechExtras, 0, newTechExtras, 0, oldTechExtras.length);
25
            newTechExtras[oldTechExtras.length] = extras;
26
            mTechExtras = newTechExtras;
27
        }
28
    }
29
}
       doRead()相关源码分析.
1
private native byte[] doRead();
2
@Override
3
public synchronized byte[] readNdef() {
4
    ......
5
    byte[] result = doRead();
6
    ......
7
    return result;
8
}
      至此和findAndReadNdef()相关的都源码进行了简单的跟踪处理。再回到前面的NfcService中的
case MSG_NDEF_TAG: 再往下就是真正分发的地方dispatchTagEndpoint了。

1
private void dispatchTagEndpoint(TagEndpoint tagEndpoint, ReaderModeParams readerParams){
2
    //Tag用来封装一个已经被发现的Tag.Tag类是framework提供的api
3
    //tagEndpoint.getTechExtras():就包含我们最后addNdefTechnology的时候存入的NdefMessage.
4
    Tag tag = new Tag(tagEndpoint.getUid(), tagEndpoint.getTechList(),
5
            tagEndpoint.getTechExtras(), tagEndpoint.getHandle(), mNfcTagService);
6
    //把tagEndpoint以 key = tagEndpoint.gethandle;value = tagEndpoint放入到集合中
7
    //final HashMap<Integer, Object> mObjectMap = new HashMap<Integer, Object>();
8
    //由此手机看来,handle一样,那么一次检测基本就存一个,第一个连接成功Tech.
9
    registerTagObject(tagEndpoint);
10
    //当有第三方app
11
    if (readerParams != null) {
12
        try {
13
            if ((readerParams.flags & NfcAdapter.FLAG_READER_NO_PLATFORM_SOUNDS) == 0) {
14
                playSound(SOUND_END);
15
            }
16
            if (readerParams.callback != null) {
17
                //调用回调onTagDiscovered.
18
                readerParams.callback.onTagDiscovered(tag);
19
                return;
20
            } else {
21
                // Follow normal dispatch below
22
            }
23
        } ...
24
    }
25
    //正真开始分发的地方.
26
    //mNfcDispatcher是NfcDispatcher实例,初始化也是在NfcService启动的时候在构造当中
27
    //mNfcDispatcher = new NfcDispatcher(mContext, mHandoverDataParser, mInProvisionMode);
28
    //传入的mHandoverDataParser = new HandoverDataParser();同样是在构造当中
29
    int dispatchResult = mNfcDispatcher.dispatchTag(tag);
30
    //分发完毕后的处理:
31
    //当失败的时候
32
    if (dispatchResult == NfcDispatcher.DISPATCH_FAIL) {
33
        unregisterObject(tagEndpoint.getHandle());
34
        //屏幕处于亮屏且解锁状态的时候:
35
        //弹出:No supported apps for this tag installed on this device
36
        //表示没有任何的activity处理当前的分发!
37
        if (mScreenState == ScreenStateHelper.SCREEN_STATE_ON_UNLOCKED) {
38
            String toastString = mContext.getString(
39
                    R.string.nfc_strings_toast_prompt_read_error_txt);
40
            //弹出Toast进行提示.
41
            if (!ToastMaster.isSameToastShown(toastString)) {
42
                ToastMaster.showToast(mContext, toastString);
43
                playSound(SOUND_ERROR);
44
            }
45
        }
46
    } else if (dispatchResult == NfcDispatcher.DISPATCH_SUCCESS) {
47
        //成功的时候,播放震动和声音.
48
        if (mAudioManager.getRingerMode() != mAudioManager.RINGER_MODE_SILENT) {
49
            mVibrator.vibrate(200);
50
        }
51
        playSound(SOUND_END);
52
    }
53
}
    可以看到最最重要的就是NfcDispatcher中的dispatchTag(Tag)了,进入到NfcDispatcher类,
此类从名字也能看出主要功能,它就是分发NFC的actions然后去开启指定的activity。
    阅读下面的流程代码之前,最好对Android NFC的TAG的分发机制有个整体了解,这样和代码对应上就更为轻松了。
整体的代码是按照Android Tag的分发优先级来决定的.
1
public int dispatchTag(Tag tag) {
2
    PendingIntent overrideIntent;
3
    IntentFilter[] overrideFilters;
4
    String[][] overrideTechLists;
5
    String[] provisioningMimes;
6
    boolean provisioningOnly;
7
    synchronized (this) {
8
        //overrideFilters的赋值是外部的app,运行在前台,想要处理Nfc的Tag使用的
9
        //外部通过调用NfcService的setForegroundDispatch来实现。
10
        overrideFilters = mOverrideFilters;
11
        overrideIntent = mOverrideIntent;
12
        overrideTechLists = mOverrideTechLists;
13
        provisioningOnly = mProvisioningOnly;
14
        provisioningMimes = mProvisioningMimes;
15
    }
16
    //在屏幕是SCREEN_STATE_ON_LOCKED的状态下尝试调用handleNfcUnlock去解锁屏幕。
17
    boolean screenUnlocked = false;
18
    if (!provisioningOnly &&
19
            mScreenStateHelper.checkScreenState() == 
20
        ScreenStateHelper.SCREEN_STATE_ON_LOCKED) {
21
        screenUnlocked = handleNfcUnlock(tag);
22
        if (!screenUnlocked) {
23
            return DISPATCH_FAIL;
24
        }
25
    }
26
    NdefMessage message = null;
27
    //将Tag解析成Ndef的格式.此处是所读取的卡片的所有Tech中只要有Ndef的Tech即可.
28
    //返回null的时候证明这个Tag不是NDEF formatted的,或者说这个Tag虽然是NDEF formatted的
29
    //但是不是Android所支持的.
30
    Ndef ndef = Ndef.get(tag);
31
    if (ndef != null) {
32
        //再通过这样获取到NdefMessage,此处的疑问,前面不是已经获取到NdefMessage
33
        //为什么还要再用NdefMessage生成个Tag,然后在通过Tag获取,看起来好像是为了方便framewok
34
        //统一接口,供外部调用.
35
        message = ndef.getCachedNdefMessage();
36
    } else {
37
        //当是null的时候,先看看是不是NfcBarcode Tech
38
        NfcBarcode nfcBarcode = NfcBarcode.get(tag);
39
        if (nfcBarcode != null && nfcBarcode.getType() == NfcBarcode.TYPE_KOVIO) {
40
            message = decodeNfcBarcodeUri(nfcBarcode);
41
        }
42
    }
43
    if (DBG) Log.d(TAG, "dispatch tag: " + tag.toString() + " message: " + message);
44
    //DispatchInfo是在Tag分发的过程中的帮助类,源码分析见后面
45
    DispatchInfo dispatch = new DispatchInfo(mContext, tag, message);
46
    //Tells the ActivityManager to resume allowing app switches.
47
    resumeAppSwitches();
48
    
49
    //如果正在运行的APP有定义了前台分发机制,则会走到这里,就是某个app注册了一些接口
50
    //并且运行在前台,它想去读取这些信息
51
    if (tryOverrides(dispatch, tag, message, overrideIntent, overrideFilters,
52
            overrideTechLists)) {
53
        return screenUnlocked ? DISPATCH_UNLOCK : DISPATCH_SUCCESS;
54
    }
55
    //尝试使用Handover来分发消息.就是带Nfc的蓝牙鼠标、键盘等.可以看到在普通的系统分发之前.
56
    //通过BT传输图片不属于这个,那个是P2P的流程中的.忽然想起来这应该就是所谓的Hadover和Beam区分吧.
57
    if (tryPeripheralHandover(message)) {
58
        if (DBG) Log.i(TAG, "matched BT HANDOVER");
59
        return screenUnlocked ? DISPATCH_UNLOCK : DISPATCH_SUCCESS;
60
    }
61
    //WIFI相关的暂无了解
62
    if (NfcWifiProtectedSetup.tryNfcWifiSetup(ndef, mContext)) {
63
        if (DBG) Log.i(TAG, "matched NFC WPS TOKEN");
64
        return screenUnlocked ? DISPATCH_UNLOCK : DISPATCH_SUCCESS;
65
    }
66
  ......
67
    //下面开始根据优先级先将Tag消息发送给对action为ACTION_NDEF_DISCOVERED感兴趣的APP处理 .
68
    if (tryNdef(dispatch, message)) {
69
        return screenUnlocked ? DISPATCH_UNLOCK : DISPATCH_SUCCESS;
70
    }
71
    //将Tag消息发送给对ACTION_TECH_DISCOVERED感兴趣的APP处理  
72
    if (tryTech(dispatch, tag)) {
73
        return DISPATCH_SUCCESS;
74
    }
75
    //如上两个action相关的activity都未处理的时候
76
    //将intent的action设置为ACTION_TAG_DISCOVERED 
77
    dispatch.setTagIntent();
78
    if (dispatch.tryStartActivity()) {
79
        if (DBG) Log.i(TAG, "matched TAG");
80
        return DISPATCH_SUCCESS;
81
    }
82
    //都无法处理就返回false.
83
    if (DBG) Log.i(TAG, "no match");
84
    return DISPATCH_FAIL;
85
}
      DispatchInfo类的源码分析:
1
/**
2
* Helper for re-used objects and methods during a single tag dispatch.
3
*/
4
static class DispatchInfo {
5
    public final Intent intent;
6
7
    final Intent rootIntent;
8
    final Uri ndefUri;
9
    final String ndefMimeType;
10
    final PackageManager packageManager;
11
    final Context context;
12
    final Tag tag;
13
14
    public DispatchInfo(Context context, Tag tag, NdefMessage message) {
15
        //构造会直接实例化一个intent,然后把tag先放入.
16
        intent = new Intent();
17
        intent.putExtra(NfcAdapter.EXTRA_TAG, tag);
18
        intent.putExtra(NfcAdapter.EXTRA_ID, tag.getId());
19
        if (message != null) {
20
            intent.putExtra(NfcAdapter.EXTRA_NDEF_MESSAGES, new NdefMessage[] {message});
21
            ndefUri = message.getRecords()[0].toUri();
22
            ndefMimeType = message.getRecords()[0].toMimeType();
23
        } else {
24
            //当传入的是null的时候,就是Ndef.get(tag)不能获取正确的值.
25
            ndefUri = null;
26
            ndefMimeType = null;
27
        }
28
        //这个NfcRootActivity会直接去启动,Intent携带的EXTRA_LAUNCH_INTENT对应的activity
29
        //对应到下面也就是启动,最一开始的intent = new Intent();
30
        //此时把你要启动的activity对应的intent添加到成员变量intent中即可.
31
        //这样好像是为了提供NFC root task.
32
        rootIntent = new Intent(context, NfcRootActivity.class);
33
        rootIntent.putExtra(NfcRootActivity.EXTRA_LAUNCH_INTENT, intent);
34
        rootIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
35
36
        this.tag = tag;
37
        this.context = context;
38
        packageManager = context.getPackageManager();
39
    }
40
    //设置注册action:ACTION_NDEF_DISCOVERED的intent.
41
    public Intent setNdefIntent() {
42
        intent.setAction(NfcAdapter.ACTION_NDEF_DISCOVERED);
43
        if (ndefUri != null) {
44
            intent.setData(ndefUri);
45
            return intent;
46
        } else if (ndefMimeType != null) {
47
            intent.setType(ndefMimeType);
48
            return intent;
49
        }
50
        return null;
51
    }
52
    //设置注册action:ACTION_TECH_DISCOVERED的intent.
53
    public Intent setTechIntent() {
54
        intent.setData(null);
55
        intent.setType(null);
56
        intent.setAction(NfcAdapter.ACTION_TECH_DISCOVERED);
57
        return intent;
58
    }
59
    //设置注册action:ACTION_TAG_DISCOVERED的intent.
60
    public Intent setTagIntent() {
61
        intent.setData(null);
62
        intent.setType(null);
63
        intent.setAction(NfcAdapter.ACTION_TAG_DISCOVERED);
64
        return intent;
65
    }
66
67
    //以成员变量intent,启动所有的注册的activity
68
    boolean tryStartActivity() {
69
        //遍历所有符合成员变量intent要求的acitivity
70
        List<ResolveInfo> activities = packageManager.queryIntentActivitiesAsUser(intent, 0,
71
                ActivityManager.getCurrentUser());
72
        if (activities.size() > 0) {
73
            //直接启动
74
            context.startActivityAsUser(rootIntent, UserHandle.CURRENT);
75
            return true;
76
        }
77
        return false;
78
    }
79
    //以特定的intentToStart,启动所有注册的activity
80
    boolean tryStartActivity(Intent intentToStart) {
81
        List<ResolveInfo> activities = packageManager.queryIntentActivitiesAsUser(
82
                intentToStart, 0, ActivityManager.getCurrentUser());
83
        if (activities.size() > 0) {
84
            rootIntent.putExtra(NfcRootActivity.EXTRA_LAUNCH_INTENT, intentToStart);
85
            context.startActivityAsUser(rootIntent, UserHandle.CURRENT);
86
            NfcIddEvent.NfcTag.dispatchedToApp(tag, activities);
87
            return true;
88
        }
89
        return false;
90
    }
91
}
     下面先介绍一个接口,用于运行在前台的app注册,拦截分发时间NfcService的setForegroundDispatch最
终会调用到NfcDispatcher中的.
1
public synchronized void setForegroundDispatch(PendingIntent intent,
2
        IntentFilter[] filters, String[][] techLists) {
3
    if (DBG) Log.d(TAG, "Set Foreground Dispatch");
4
    mOverrideIntent = intent;
5
    mOverrideFilters = filters;
6
    mOverrideTechLists = techLists;
7
}
第三方app使用前台分发系统时的调用
1
boolean tryOverrides(DispatchInfo dispatch, Tag tag, NdefMessage message, PendingIntent overrideIntent,
2
        IntentFilter[] overrideFilters, String[][] overrideTechLists) {
3
    ......
4
    // 首先是当NdefMessage存在的时候,先去判断NDEF格式的消息
5
    if (message != null) {
6
        intent = dispatch.setNdefIntent();
7
        //当当前的NdefMessage中是对应的NDEF消息时,使用传入的PendingIntent去启动对应的activity
8
        if (intent != null &&
9
                isFilterMatch(intent, overrideFilters, overrideTechLists != null)) {
10
            try {
11
                //直接启动
12
                overrideIntent.send(mContext, Activity.RESULT_OK, intent);
13
                if (DBG) Log.i(TAG, "matched NDEF override");
14
                return true;
15
            } catch (CanceledException e) {
16
                return false;
17
            }
18
        }
19
    }
20
    // TECH
21
    intent = dispatch.setTechIntent();
22
    //当传入的Tag的Technolg也是支持的时候,把action设置成ACTION_NDEF_DISCOVERED去启动
23
    if (isTechMatch(tag, overrideTechLists)) {
24
        try {
25
            overrideIntent.send(mContext, Activity.RESULT_OK, intent);
26
            if (DBG) Log.i(TAG, "matched TECH override");
27
            return true;
28
        } catch (CanceledException e) {
29
            return false;
30
        }
31
    }
32
    // TAG 和上面同理。
33
    intent = dispatch.setTagIntent();
34
    if (isFilterMatch(intent, overrideFilters, overrideTechLists != null)) {
35
        try {
36
            overrideIntent.send(mContext, Activity.RESULT_OK, intent);
37
            if (DBG) Log.i(TAG, "matched TAG override");
38
            return true;
39
        } catch (CanceledException e) {
40
            return false;
41
        }
42
    }
43
    return false;
44
}
      接下来是通过tryPeripheralHandover的,就是交由Bt进行发送的数据的处理
1
public boolean tryPeripheralHandover(NdefMessage m) {
2
    //消息为空,或者说设备不支持蓝牙,那么就直接返回
3
    if (m == null || !mDeviceSupportsBluetooth) return false;
4
    if (DBG) Log.d(TAG, "tryHandover(): " + m.toString());
5
    //假如是进行Handover的时候,会按照Nfc Form中的Handover相关的协议从NdefMessage中解析出正确的数据
6
    HandoverDataParser.BluetoothHandoverData handover = 
7
        mHandoverDataParser.parseBluetooth(m);
8
    ......
9
    //得到handover的各个参数以后,设置到intent内,并启动PeripheralHandoverService这个service.
10
    //通过下面可以看到,主要有BT的 device、name、uuid、等
11
    Intent intent = new Intent(mContext, PeripheralHandoverService.class);
12
    intent.putExtra(PeripheralHandoverService.EXTRA_PERIPHERAL_DEVICE, handover.device);
13
    intent.putExtra(PeripheralHandoverService.EXTRA_PERIPHERAL_NAME, handover.name);
14
    intent.putExtra(PeripheralHandoverService.EXTRA_PERIPHERAL_TRANSPORT, 
15
                    handover.transport);
16
    if (handover.oobData != null) {
17
        intent.putExtra(PeripheralHandoverService.EXTRA_PERIPHERAL_OOB_DATA, 
18
                        handover.oobData);
19
    }
20
    if (handover.uuids != null) {
21
        intent.putExtra(PeripheralHandoverService.EXTRA_PERIPHERAL_UUIDS, handover.uuids);
22
    }
23
    if (handover.bluetoothClass != null) {
24
        intent.putExtra(PeripheralHandoverService.EXTRA_PERIPHERAL_CLASS, 
25
                        handover.bluetoothClass);
26
    }
27
    intent.putExtra(PeripheralHandoverService.EXTRA_CLIENT, mMessenger);
28
    intent.putExtra(PeripheralHandoverService.EXTRA_BT_ENABLED, 
29
                    mBluetoothEnabledByNfc.get());
30
    //国内过CTA检测的时候的弹框
31
    if (CtaUtils.showCtaBtDialogIfNeeded(mContext, null, intent, null)) {
32
        return true;
33
    }
34
    //最后启动PeripheralHandoverService.
35
    mContext.startServiceAsUser(intent, UserHandle.CURRENT);
36
    return true;
37
}
      关于PeripheralHandoverService的介绍
     这个service主要是用于负责Handover,也就是链接蓝牙键盘、Speaker等.
1
public class PeripheralHandoverService extends Service 
2
            implements BluetoothPeripheralHandover.Callback {
3
    ......
4
    public PeripheralHandoverService() {
5
        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
6
        mHandler = new MessageHandler();
7
        mMessenger = new Messenger(mHandler);
8
        mBluetoothHeadsetConnected = false;
9
        mBluetoothEnabledByNfc = false;
10
        mStartId = 0;
11
    }
12
    @Override
13
    public void onCreate() {
14
        super.onCreate();
15
        mNfcAdapter = NfcAdapter.getDefaultAdapter(getApplicationContext());
16
        //注册一个广播监听蓝牙状态,是否打开等.
17
        IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
18
        registerReceiver(mBluetoothStatusReceiver, filter);
19
    }
20
21
    @Override
22
    public int onStartCommand(Intent intent, int flags, int startId) {
23
        ......
24
        //进一步的回去打开BT,前面也注册了广播,在收到蓝牙开启广播以后开始做真正的Handover
25
        //去连接键盘了,等等.
26
        if (doPeripheralHandover(intent.getExtras())) {
27
            return START_STICKY;
28
        }
29
        ......
30
    }
31
}
        Handover到时候专门在分析源码相关的源码,此处我们回到前面的dispatchTag()方法中,然后就是
按照Android的分发系统,优先处理注册了action为NfcAdapter.ACTION_NDEF_DISCOVERED的
1
    boolean tryNdef(DispatchInfo dispatch, NdefMessage message) {
2
        ......
3
        //为dispatch设置ACTION_NDEF_DISCOVERED相关的intent.
4
        Intent intent = dispatch.setNdefIntent();
5
        if (intent == null) return false;
6
        //如果发送的NdefMessage包含打开这个消息的包的信息(AAR)
7
        //那么就用指定的包处理这个Tag消息
8
        List<String> aarPackages = extractAarPackages(message);
9
        for (String pkg : aarPackages) {
10
            dispatch.intent.setPackage(pkg);
11
            //直接使用指定的apk去打开
12
            if (dispatch.tryStartActivity()) {
13
                if (DBG) Log.i(TAG, "matched AAR to NDEF");
14
                return true;
15
            }
16
        }
17
        //到下面应该aar包中没有对ACTION_NDEF_DISCOVERED这个action感兴趣的activity.
18
        //然后就区启动aar中的第一个包含的apk
19
        // Try to perform regular launch of the first AAR
20
        if (aarPackages.size() > 0) {
21
            String firstPackage = aarPackages.get(0);
22
            PackageManager pm;
23
            try {
24
                UserHandle currentUser = new UserHandle(ActivityManager.getCurrentUser());
25
                pm = mContext.createPackageContextAsUser("android", 0,
26
                        currentUser).getPackageManager();
27
            } ...
28
            
29
            Intent appLaunchIntent = pm.getLaunchIntentForPackage(firstPackage);
30
            if (appLaunchIntent != null && dispatch.tryStartActivity(appLaunchIntent)) {
31
                if (DBG) Log.i(TAG, "matched AAR to application launch");
32
                return true;
33
            }
34
            // Find the package in Market: (看这架势让我们去下载呀,这么流氓哈)
35
            Intent marketIntent = getAppSearchIntent(firstPackage);
36
            if (marketIntent != null && dispatch.tryStartActivity(marketIntent)) {
37
                if (DBG) Log.i(TAG, "matched AAR to market launch");
38
                return true;
39
            }
40
        }
41
        ......
42
        //当消息中没有包名的时候,就用前面设置的intent:setNdefIntent
43
        //来启动activity,所以此时所有注册的activity都会受到这个action,然后你可以选择用那个启动
44
        dispatch.intent.setPackage(null);
45
        if (dispatch.tryStartActivity()) {
46
            if (DBG) Log.i(TAG, "matched NDEF");
47
            return true;
48
        }
49
        return false;
50
    }
    而tryTech()的思想是一样的,也是经过一系列判断后,通过dispatch.tryStartActivity()来启动,不过它启动
是action为NfcAdapter.ACTION_TECH_DISCOVERED的,不再赘述。
    当都不能处理的时候就调用dispatch.setTagIntent()把intent设置NfcAdapter.ACTION_TAG_DISCOVERED
用它去启动符合要求的activity,在启动失败的时候就会返回分发失败的状态.
    至此完成整体Tag的读取分发系统.

2、写入Tag的简单流程
  写开发时app调用framework层的对应的不同协议的Tag代表的类的接口有如下:
     位于:android/frameworks/base/core/java/android/nfc/tech
    有:  NfcA.java、NfcB.java、NfcF.java、def.java、IsoDep.java ...  等等。
这些类都代表了指定的不同协议的Tag的实现.此处我们以android中的Ndef为例,你想要写入数据的
时候,调用Ndef类的如下接口,第三方写入的时候的过程(???具体前奏还不太清楚)
1
public void writeNdefMessage(NdefMessage msg) throws IOException, FormatException {
2
    checkConnected();
3
    try {
4
        //tagServices 在 packages/app/Nfc中实现的
5
        INfcTag tagService = mTag.getTagService();
6
        ......
7
        int serviceHandle = mTag.getServiceHandle();
8
        if (tagService.isNdef(serviceHandle)) {
9
            //调用tagService的ndefWrite实现真正的写入
10
            int errorCode = tagService.ndefWrite(serviceHandle, msg);
11
            switch (errorCode) {
12
                case ErrorCodes.SUCCESS:
13
                    break;
14
                case ErrorCodes.ERROR_IO:
15
                    throw new IOException();
16
                case ErrorCodes.ERROR_INVALID_PARAM:
17
                    throw new FormatException();
18
                default:
19
                    // Should not happen
20
                    throw new IOException();
21
            }
22
        }
23
        ......
24
    } catch (RemoteException e) {
25
        Log.e(TAG, "NFC service dead", e);
26
    }
27
}
    那么我们就需要去packages/app/Nfc当中找INfcTag的具体实现了,是位于NfcService当中的内部类
final class TagService extends INfcTag.Stub调用内部方法ndefWrite
1
    @Override
2
    public int ndefWrite(int nativeHandle, NdefMessage msg) throws RemoteException {
3
        NfcPermissions.enforceUserPermissions(mContext);
4
        
5
        TagEndpoint tag;
6
        ......
7
        //下面是真正的写入的地方    
8
        if (tag.writeNdef(msg.toByteArray())) {
9
            return ErrorCodes.SUCCESS;
10
        } else {
11
            return ErrorCodes.ERROR_IO;
12
        }
13
    }
    前面我们已经说过TagEndpoint是有NativeNfcTag实现的,对应的方法如下
1
private native boolean doWrite(byte[] buf);
2
@Override
3
public synchronized boolean writeNdef(byte[] buf) {
4
    if (mWatchdog != null) {
5
        mWatchdog.pause();
6
    }
7
    //可以看到去native层进行进一步的读写!
8
    boolean result = doWrite(buf);//go to the native
9
    if (mWatchdog != null) {
10
        mWatchdog.doResume();
11
    }
12
    return result;
13
}
至此java层的写入流程就分析完毕了。
  下面是调试的时候一次写入的Log记录一下,会先调用链接,再调用transceive,最后再写入。
1
04-21 00:37:02.032 D/zy      ( 2652): Nfcervice  connect 
2
04-21 00:37:02.042 D/zy      ( 2652): NativeNfc transceive 
3
04-21 00:37:02.070 D/zy      ( 2652): Nfcervice  connect 
4
04-21 00:37:02.094 D/zy      ( 2652): Nfcervice  ndefWrite 
5
04-21 00:37:02.094 D/zy      ( 2652): NativeNfc writeNdef