1 NFC代码位置
手机中的NFC主要分为两大部分:Framework框架层的NFC部分和应用侧的 NFC部分。
Framework框架层的NFC部分主要是作为调用NFC方法的客户端,提供给用户操作 NFC 的接口,代码位于:
/frameworks/base/core/java/android/nfc
NFC服务的服务端以及主要处理方法都在应用侧的NFC模块中,代码位于:/packages/apps/nfc
nci(NFCController Interface)是指NFC控制接口规范。
nxp是恩智浦的缩写,存放的是恩智浦公司所制定的NFC接口规范。
查看Android.mk可以看到:
$(callall-java-files-under, nci)
在编译的时候只引入src和nci下的java文件,不考虑nxp下的代码1 NFC的启动(Java方式)1.1 服务端的启动:由于NFC服务的服务端是放在应用层的NFC内的,所以NFC的启动是从NFC应用的启动开始的。
查看应用侧NFC模块的AndroidManifest.xml文件,可以看到
……
android:persistent="true"
android:backupAgent="com.android.nfc.NfcBackupAgent"
android:killAfterRestore="false"
android:usesCleartextTraffic="false"
>
属性android:persistent="true",即该NFC应用会开机自启动。
在NfcApplication中的onCreate方法内,实例化了NfcService
public class NfcApplicationextends Application
{
……
@Override
publicvoid onCreate()
{
super.onCreate();
……
if(UserHandle.myUserId()== 0 && isMainProcess)
{
mNfcService=new NfcService(this);
ThreadedRenderer.enableForegroundTrimming();
}
}
}NfcService的构造方法中,实例化了NfcAdapterService对象,该对象即是NfcAdapter的服务端,包含了主要的NFC处理逻辑。之后将该Service通过addService添加到了ServiceManager中。
在该构造方法内,同时也实例化了NativeNfcManager,通过该步骤加载了jni并注册了native方法。
public NfcService(ApplicationnfcApplication)
{
mUserId=ActivityManager.getCurrentUser();
mContext=nfcApplication;
mNfcAdapter=new NfcAdapterService();
……
mDeviceHost=new NativeNfcManager(mContext, this);
//Make sure this is only called when object construction is complete.
ServiceManager.addService(SERVICE_NAME,mNfcAdapter);
……
}
至此,系统将NFC的服务注册到了系统中。
1.2 客户端的启动:在ContextImpl类中,使用到了SystemServiceRegistry类。
final Object[]mServiceCache = SystemServiceRegistry.createServiceCache();
在SystemServiceRegistry类中首先会执行静态块中的方法,构造了NfcManager对象,注册NFC_SERVICE。
private SystemServiceRegistry() { }
static
{
…
registerService(Context.NFC_SERVICE, NfcManager.class,
new CachedServiceFetcher
{
@Override
public NfcManager createService(ContextImpl ctx)
{
return new NfcManager(ctx);
}
});
…}
之后便能够通过getSystemService获得NfcManager。
在NfcManager的构造方法内,实例化了NfcAdapter对象并保存,便于之后获得fcAdapter。
public final class NfcManager {
private final NfcAdapter mAdapter;
public NfcManager(Context context)
{
NfcAdapteradapter;
context = context.getApplicationContext();
……
Try
{
adapter = NfcAdapter.getNfcAdapter(context);
}catch (UnsupportedOperationException e)
{
adapter = null;
}mAdapter = adapter;
}
public NfcAdapter getDefaultAdapter()
{
return mAdapter;
}
}NfcAdapter的getNfcAdapter方法中,通过getServiceInterface来获得NfcAdapterService。
这样,之后便能够通过NfcAdapter对象来远程调用NfcAdapterSerice的方法了。
public static synchronized NfcAdapter getNfcAdapter(Contextcontext)
{
……
sService = getServiceInterface();
……
NfcAdapteradapter = sNfcAdapters.get(context);
if (adapter== null)
{
adapter= new NfcAdapter(context);
sNfcAdapters.put(context, adapter);
}
return adapter;
}
getServiceInterface方法中通过ServiceManager.getService("nfc")获得NfcAdapterSerice。
private static INfcAdapter getServiceInterface()
{
/*get a handle to NFC service */
IBinderb = ServiceManager.getService("nfc");
if (b== null)
{
return null;
}return INfcAdapter.Stub.asInterface(b);
}1.3 NFC方法的调用:由以上的代码可知,我们可以通过以下方法获取NfcAdapter。
NfcManager nfcManager =(NfcManager) getSystemService(NFC_SERVICE);
NfcAdapter nfcAdapter =nfcManager.getDefaultAdapter();
也可以通过如下代码来获得NfcAdapter并调用NFC的方法。
NfcAdapter nfc =NfcAdapter.getDefaultAdapter(mContext);
在NfcAdapter的getDefaultAdapter方法中,我们首先获得了NfcManager,之后调用了NfcManager的getDefaultAdapter方法。这和第一种获得NfcAdapter的方式是一样的。之后在NfcManager中,会返回之前实例化NfcManager时所创建的NfcAdapter对象。由此,我们得到了NfcAdapter对象。
public static NfcAdaptergetDefaultAdapter(Context context)
{
if(context== null)
{
throw new IllegalArgumentException("contextcannot be null");
}context= context.getApplicationContext(); NfcManager manager= (NfcManager) context.getSystemService(Context.NFC_SERVICE);
if (manager == null)
{
return null;
}return manager.getDefaultAdapter();
}
2 NFC的启动(Native):NFC作为一个手机外设,自然存在设备驱动程序,因而NFC模块除了java代码之外还存在native层。
实际上NFC服务的启动包括NFC java服务的注册和native层的启动,native层的启动是紧跟NfcAdapterService的注册的。
接下来将对NFC的native层启动的代码进行分析。
在NfcService的构造函数里,除了实例化了NfcAdapterService对象之外,还实例化了NativeNfcManager对象。
public NfcService(Application nfcApplication)
{
mUserId = ActivityManager.getCurrentUser();
mContext = nfcApplication;
mNfcTagService = new TagService();
mNfcAdapter = new NfcAdapterService();
sService = this;
……
mDeviceHost = new NativeNfcManager(mContext,this);
ServiceManager.addService(SERVICE_NAME,mNfcAdapter);
newEnableDisableTask().execute(TASK_BOOT);// do blocking boot tasks
mHandler.sendEmptyMessageDelayed(MSG_UPDATE_STATS,STATS_UPDATE_INTERVAL_MS);
}
在NativeNfcManager中的静态块中会首先去加载nfc_nci_jni,之后注册Native的方法。
Static
{
System.loadLibrary("nfc_nci_jni");
}加载jni后会回调JNI_OnLoad方法,该方法中再去执行了一些注册方法。
jint JNI_OnLoad (JavaVM* jvm,void*)
{
JNIEnv*e = NULL;
// Check JNIversion
if (jvm->GetEnv ((void **)&e, JNI_VERSION_1_6))
return JNI_ERR;
if (android::register_com_android_nfc_NativeNfcManager(e) == -1)return JNI_ERR;
if (android::register_com_android_nfc_NativeLlcpServiceSocket(e) == -1)return JNI_ERR;
……return JNI_VERSION_1_6;
}
register_com_android_nfc_NativeNfcManager方法中会通过jniRegisterNativeMethods方法将NativeNfcManager中的java方法与jni中的native方法对应起来。
intregister_com_android_nfc_NativeNfcManager (JNIEnv *e)
{
PowerSwitch::getInstance().initialize (PowerSwitch::UNKNOWN_LEVEL);
return jniRegisterNativeMethods (e, gNativeNfcManagerClassName, gMethods,NELEM (gMethods));
}
将NativeNfcManager中的java方法与jni中的native方法对应起来,之后在java文件中便可以调用Native的方法了。
static JNINativeMethod gMethods[] =
{
{"doDownload","()Z", (void*)nfcManager_doDownload},
{"initializeNativeStructure","()Z",(void*)nfcManager_initNativeStruc},
{"doInitialize","()Z",
(void*)nfcManager_doInitialize},
……
}
继续查看NativeNfcManager类,在构造方法内执行了initializeNativeStructure,该方法是一个Natvie的方法。
public NativeNfcManager(Context context,DeviceHostListener listener)
{
mListener = listener;
initializeNativeStructure();
mContext = context;
}
public native boolean initializeNativeStructure();
根据gMethods中的定义,initializeNativeStructure会对应到nfcManager_initNativeStruc方法。在nfcManager_initNativeStruc方法中将NFC模块中的java方法与Native方法对应起来。这样当底层NFC模块进行处理后,便能够通过native层调用到java层的对应方法,来通知上层NFC模块进行下一步的处理,如发送广播等。例如notifyNdefMessageListeners方法,该方法是手机作为读卡器模式下读到tag后会调用的方法。
static jboolean nfcManager_initNativeStruc(JNIEnv* e, jobject o)
{
……
/*Initialize native cached references */
gCachedNfcManagerNotifyNdefMessageListeners = e->GetMethodID(cls.get(),
"notifyNdefMessageListeners","(Lcom/android/nfc/dhimpl/NativeNfcTag;)V"); gCachedNfcManagerNotifyLlcpLinkActivation=e->GetMethodID(cls.get(),
"notifyLlcpLinkActivation","(Lcom/android/nfc/dhimpl/NativeP2pDevice;)V");
gCachedNfcManagerNotifyLlcpLinkDeactivated=e->GetMethodID(cls.get(),
"notifyLlcpLinkDeactivated","(Lcom/android/nfc/dhimpl/NativeP2pDevice;)V");
……
return JNI_TRUE;
}
这样,NFC的native层的初始化便完成了,在该流程中,主要去加载了jni,并将java方法与native方法一一对应了起来,之后NFC的上层模块便能够与底层模块通过native层相互调用了。在使用场景中,手机NFC的打开和关闭这类用户操作,是java层向native层进行调用。而NFC刷卡,被刷则是native层向java层进行调用。
3 NFC的打开调用NfcAdapter的enable方法后,远程调用到NfcAdapterService的enable方法。
final class NfcAdapterServiceextends INfcAdapter.Stub
{
@Override
publicboolean enable() throws RemoteException
{
NfcPermissions.enforceAdminPermissions(mContext);
//保存NFC打开或者关闭的状态
saveNfcOnSetting(true);
//调用task打开NFC
new EnableDisableTask().execute(TASK_ENABLE);
return true;
}
……
}
之后调用了enableInternal方法,该方法中调用了initialize方法。
booleanenableInternal()
{
……
try
{
if (!mDeviceHost.initialize())
{
updateState(NfcAdapter.STATE_OFF);
return false;
}
}finally
{
mRoutingWakeLock.release();
}……
}
mDeviceHost是一个NativeNfcManager对象,initialize方法中执行的doInitialize则对应一个native的方法。
privatenative boolean doInitialize();
@Override
publicboolean initialize()
{
return doInitialize();
}doInitialize对应了native层的nfcManager_doInitialize(JNIEnv* e, jobject o)方法,该方法内主要执行了
stat = NFA_Enable(nfaDeviceManagementCallback, nfaConnectionCallback);
通过该语句绑定了nfaConnectionCallback回调方法,在nfaConnectionCallback内会接收event如读取到tag,检测到RFID场等。到此,手机的NFC功能便打开了,之后NFC底层模块检测到相关的event后便调用相应的native方法进而调用到java层的方法,从而通知手机上层对应的NFC事件。
4 手机NFC刷卡手机NFC的刷卡是一个自下而上的过程,由设备读到卡后,通过native层调用java方法,进而告知上层刷卡事件。
在nfaConnectionCallback收到刷卡的event,对应执行
NfcTag::getInstance().connectionEventHandler(connEvent, eventData);
接下来,在NfcTag.cpp的connectionEventHandler方法内,执行了createNativeNfcTag
void NfcTag::connectionEventHandler(UINT8 event, tNFA_CONN_EVT_DATA* data)
{
static const charfn []= "NfcTag::connectionEventHandler";
switch (event)
{
……
caseNFA_ACTIVATED_EVT:
//Only do tag detection if we are polling and it is not ´EE Direct RF´ activation
//(which may happen when we are activated as a tag).
……
createNativeNfcTag(activated);
}
break;
之后,则调用方法gCachedNfcManagerNotifyNdefMessageListeners
e->CallVoidMethod(mNativeData->manager,android::gCachedNfcManagerNotifyNdefMessageListeners, tag.get());
该方法对应了java中的notifyNdefMessageListeners方法。之后回到了NativeNfcManager类中
privatevoid notifyNdefMessageListeners(NativeNfcTag tag)
{
mListener.onRemoteEndpointDiscovered(tag);
}该mListener即是NfcService,在NfcService中发送了MSG_NDEF_TAG的message。
@Override
publicvoid onRemoteEndpointDiscovered(TagEndpoint tag)
{
sendMessage(NfcService.MSG_NDEF_TAG,tag);
}在handler处理MSG_NDEF_TAG时,主要执行了dispatchTagEndpoint方法,该方法内去执行mNfcDispatcher.dispatchTag(tag);该方法将tag以广播的形式发送出来,发送的广播action为
publicstatic final String ACTION_NDEF_DISCOVERED ="android.nfc.action.NDEF_DISCOVERED";
这样,手机上安装的其他NFC应用接到该广播,便会从tag中取出NdefMessage并进行对应的处理。





































苏公安网备 32011402010933号