在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其他核心类,以及传输相关的内容。