前面介绍过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,一大波代码马上到来:
-
{
-
mUserId = ActivityManager.getCurrentUser();
-
mContext = nfcApplication;
-
-
//@paul: Tag相关; extend INfcTag;最终调用到NativeNfcTag
-
mNfcTagService = new TagService();
-
//@paul: 上层APP 调用 NFC 功能时, 中间变量adapter;extend INfcAdaptor;最终调用到NfcAdaptor
-
mNfcAdapter = new NfcAdapterService();
-
Log.i(TAG, "Starting NFC service");
-
-
sService = this;
-
//@paul: NFC与屏幕解锁的关系,含OFF / ON_LOCK / ON_UNLOCK
-
mScreenStateHelper = new ScreenStateHelper(mContext);
-
mContentResolver = mContext.getContentResolver();
-
//@paul: 底层Driver 相关的JNI 接口
-
mDeviceHost = new NativeNfcManager(mContext, this);
-
//@paul: 还不懂
-
mNfcUnlockManager = NfcUnlockManager.getInstance();
-
//@paul: 和handover 相关接口;主要是bluetooth, 实际上wifi 也是可以实现的
-
mHandoverManager = new HandoverManager(mContext);
-
boolean isNfcProvisioningEnabled = false;
-
try {
-
isNfcProvisioningEnabled = mContext.getResources().getBoolean(
-
R.bool.enable_nfc_provisioning);
-
} catch (NotFoundException e) {
-
}
-
//@paul: 设备是否在setup wizard阶段支持接收NFC 数据
-
if (isNfcProvisioningEnabled) {
-
mInProvisionMode = Settings.Secure.getInt(mContentResolver,
-
Settings.Global.DEVICE_PROVISIONED, 0) == 0;
-
} else {
-
mInProvisionMode = false;
-
}
-
//@paul: 收到NFC 消息处理流程, 最终调用到dispatchTag()
-
mNfcDispatcher = new NfcDispatcher(mContext, mHandoverManager, mInProvisionMode);
-
//@paul: 基于LLCP 连接的服务,含NdefPushService/SnepService/P2pEventManager
-
//@paul: 此类会定义doPut/doGet, 后续还会提到
-
mP2pLinkManager = new P2pLinkManager(mContext, mHandoverManager,
-
mDeviceHost.getDefaultLlcpMiu(), mDeviceHost.getDefaultLlcpRwSize());
-
//@paul: 获取shared_pref 信息,一般存储位置在/data/data/<包名>/shared_prefs
-
mPrefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE);
-
mPrefsEditor = mPrefs.edit();
-
-
//@paul: 和security相关,主要是读取解析/etc/nfcee_access.xml文件
-
mNfceeAccessControl = new NfceeAccessControl(mContext);
-
-
mState = NfcAdapter.STATE_OFF;
-
//@paul: 依prefs 文件定义,检查NdefPush 是否enable
-
mIsNdefPushEnabled = mPrefs.getBoolean(PREF_NDEF_PUSH_ON, NDEF_PUSH_ON_DEFAULT);
-
setBeamShareActivityState(mIsNdefPushEnabled);
-
-
mIsDebugBuild = "userdebug".equals(Build.TYPE) || "eng".equals(Build.TYPE);
-
//@paul: 电源管理模块,主要是屏幕状态与NFC 是否响应有关系
-
mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
-
//@paul: 获取WakeLock
-
// 步骤:1.获取powermanager 实例
-
// 2.生成实例: new WakeLock
-
// 3.通过acquire() 获取锁
-
mRoutingWakeLock = mPowerManager.newWakeLock(
-
PowerManager.PARTIAL_WAKE_LOCK, "NfcService:mRoutingWakeLock");
-
//@paul: 屏幕锁
-
mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
-
mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-
-
mScreenState = mScreenStateHelper.checkScreenState();
-
//@Paul: 将NFC 加入到系统service中
-
ServiceManager.addService(SERVICE_NAME, mNfcAdapter);
-
-
// Intents for all users
-
//@paul: 注册屏幕亮/灭,用户激活和切换
-
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
-
filter.addAction(Intent.ACTION_SCREEN_ON);
-
filter.addAction(Intent.ACTION_USER_PRESENT);
-
filter.addAction(Intent.ACTION_USER_SWITCHED);
-
registerForAirplaneMode(filter);
-
mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, null);
-
-
IntentFilter ownerFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
-
ownerFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
-
mContext.registerReceiver(mOwnerReceiver, ownerFilter);
-
-
//@paul: 关注程序安装和卸载
-
ownerFilter = new IntentFilter();
-
ownerFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
-
ownerFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
-
ownerFilter.addDataScheme( "package");
-
mContext.registerReceiver(mOwnerReceiver, ownerFilter);
-
-
updatePackageCache();
-
-
PackageManager pm = mContext.getPackageManager();
-
//@paul: 判断系统是否支持卡模拟
-
mIsHceCapable = pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION);
-
if (mIsHceCapable) {
-
mCardEmulationManager = new CardEmulationManager(mContext);
-
}
-
mForegroundUtils = ForegroundUtils.getInstance();
-
//@paul: 开始执行NFC , 参数TASK_BOOT
-
new EnableDisableTask().execute(TASK_BOOT); // do blocking boot tasks
-
}
看完这么多的代码,是不是还不确定各个部分的意义。没有关系,继续挖。
1. TagService
此部分实现的接口都在INfcTag.aidl中定义,接口如下:
-
{
-
int close(int nativeHandle);
-
int connect(int nativeHandle, int technology);
-
int reconnect(int nativeHandle);
-
int[] getTechList( int nativeHandle);
-
boolean isNdef(int nativeHandle);
-
boolean isPresent(int nativeHandle);
-
TransceiveResult transceive(int nativeHandle, in byte[] data, boolean raw);
-
NdefMessage ndefRead(int nativeHandle);
-
int ndefWrite(int nativeHandle, in NdefMessage msg);
-
int ndefMakeReadOnly(int nativeHandle);
-
boolean ndefIsWritable(int nativeHandle);
-
int formatNdef(int nativeHandle, in byte[] key);
-
Tag rediscover(int nativehandle);
-
int setTimeout(int technology, int timeout);
-
int getTimeout(int technology);
-
void resetTimeouts();
-
boolean canMakeReadOnly(int ndefType);
-
int getMaxTransceiveLength(int technology);
-
boolean getExtendedLengthApdusSupported();
-
}
以其中connect()函数为例,解释一下此部分的流程和逻辑,其余的函数基本上可以参考connect()函数:
-
-
public int connect(int nativeHandle, int technology) throws RemoteException {
-
//@paul: 检查manifest中是否有nfc操作权限
-
NfcPermissions.enforceUserPermissions(mContext);
-
-
TagEndpoint tag = null;
-
//@paul: 判断NFC是否启动,在执行enableInternal()时,条件为真
-
if (!isNfcEnabled()) {
-
return ErrorCodes.ERROR_NOT_INITIALIZED;
-
}
-
-
/* find the tag in the hmap */
-
tag = (TagEndpoint) findObject(nativeHandle);
-
if (tag == null) {
-
return ErrorCodes.ERROR_DISCONNECT;
-
}
-
//@paul: 判断Tag是否还在范围内,NativeNfcTag会自动更新连接的标记
-
if (!tag.isPresent()) {
-
return ErrorCodes.ERROR_DISCONNECT;
-
}
-
-
// Note that on most tags, all technologies are behind a single
-
// handle. This means that the connect at the lower levels
-
// will do nothing, as the tag is already connected to that handle.
-
//@paul: NativeNfcTag中定义了connect函数,最终调用到doConnect()
-
if (tag.connect(technology)) {
-
return ErrorCodes.SUCCESS;
-
} else {
-
return ErrorCodes.ERROR_DISCONNECT;
-
}
-
}
上述函数中的tag.connect()最终调用到NativeNfcTag.java中的connect,此处的调用就是aidl实现的。 下面以NXP的流程介绍一下NativeNfcTag.java中的connect。
-
-
public synchronized boolean connect(int technology) {
-
return connectWithStatus(technology) == 0;
-
}
看起来还要继续挖:
-
private native int doConnect(int handle);
-
public synchronized int connectWithStatus(int technology) {
-
if (technology == TagTechnology.NFC_B) {
-
// Not supported by PN544
-
//@paul: 芯片特性,不支持怎么的
-
return - 1;
-
}
-
if (mWatchdog != null) {
-
mWatchdog.pause();
-
}
-
int status = - 1;
-
for ( int i = 0; i < mTechList.length; i++) {
-
if (mTechList[i] == technology) {
-
// Get the handle and connect, if not already connected
-
if (mConnectedHandle != mTechHandles[i]) {
-
// We're not yet connected to this handle, there are
-
// a few scenario's here:
-
// 1) We are not connected to anything yet - allow
-
// 2) We are connected to a technology which has
-
// a different handle (multi-protocol tag); we support
-
// switching to that.
-
if (mConnectedHandle == - 1) {
-
// Not connected yet
-
//@paul: 如果是没有连接过,则直接调用到doConnect()
-
status = doConnect(mTechHandles[i]);
-
} else {
-
// Connect to a tech with a different handle
-
status = reconnectWithStatus(mTechHandles[i]);
-
}
-
if (status == 0) {
-
mConnectedHandle = mTechHandles[i];
-
mConnectedTechIndex = i;
-
}
-
} else {
-
......
-
}
-
break;
-
}
-
}
-
if (mWatchdog != null) {
-
mWatchdog.doResume();
-
}
-
return status;
-
}
看了这么多,重要的就是最后的doConnect(),这个是JNI的一个接口:
-
{ "doConnect", "(I)I",
-
( void *)com_android_nfc_NativeNfcTag_doConnect},
继续挖吧:
-
static jint com_android_nfc_NativeNfcTag_doConnect(JNIEnv *e,jobject o, phLibNfc_Handle handle)
-
{
-
jint status;
-
struct nfc_jni_callback_data cb_data;
-
phLibNfc_sRemoteDevInformation_t* pRemDevInfo = NULL;
-
-
CONCURRENCY_LOCK();
-
-
/* Create the local semaphore */
-
if (!nfc_cb_data_init(&cb_data, &pRemDevInfo))
-
{
-
status = NFCSTATUS_NOT_ENOUGH_MEMORY;
-
goto clean_and_return;
-
}
-
-
TRACE( "phLibNfc_RemoteDev_Connect(RW)");
-
REENTRANCE_LOCK();
-
storedHandle = handle;
-
status = phLibNfc_RemoteDev_Connect(handle, nfc_jni_connect_callback,( void *)&cb_data);
-
......
-
-
/* Connect Status */
-
if(status != NFCSTATUS_SUCCESS)
-
{
-
goto clean_and_return;
-
}
-
-
// Success, set poll & act bytes
-
set_target_pollBytes(e, o, pRemDevInfo);
-
set_target_activationBytes(e, o, pRemDevInfo);
-
-
clean_and_return:
-
nfc_cb_data_deinit(&cb_data);
-
CONCURRENCY_UNLOCK();
-
return status;
-
}
此部分定义的接口主要是提供给上层,接口定义在INfcAdaptor.aidl中,目的是透过该接口,可以直接操作Framework中的API,最终调用到JNI层。INfcAdaptor中接口如下:
-
{
-
//@paul: 获取NfcService中初始化的mNfcTagService
-
INfcTag getNfcTagInterface();
-
//@paul: 获取NfcService中初始化的mCardEmulationInterface
-
INfcCardEmulation getNfcCardEmulationInterface();
-
//@paul: AOSP默认不支持
-
INfcAdapterExtras getNfcAdapterExtrasInterface(in String pkg);
-
//@paul: 获取NFC当前状态
-
int getState();
-
//@paul: 关闭NFC功能
-
boolean disable(boolean saveState);
-
//@paul: 启动NFC功能
-
boolean enable();
-
//@paul: 更新prefs中ndef值,同时启动p2p发送功能service
-
boolean enableNdefPush();
-
//@paul: 更新prefs中ndef值,同时关闭p2p发送功能service
-
boolean disableNdefPush();
-
//@paul: NdefPush功能是否打开
-
boolean isNdefPushEnabled();
-
//@paul: 启动底层polling流程,最终会调用到JNI,到Driver
-
void pausePolling(int timeoutInMs);
-
void resumePolling();
-
//@paul: 写APP时候的常用方法,设置此函数后,收到的消息会只在前台的APP处理
-
void setForegroundDispatch(in PendingIntent intent,in IntentFilter[] filters, in TechListParcel techLists);
-
//@paul: 上层APP设置回调,用于Beam过程中产生shareData
-
void setAppCallback(in IAppCallback callback);
-
//@paul: 启动Beam流程
-
oneway void invokeBeam();
-
oneway void invokeBeamInternal(in BeamShareData shareData);
-
//@paul: 分发收到的tag信息
-
void dispatch(in Tag tag);
-
void setReaderMode (IBinder b, IAppCallback callback, int flags, in Bundle extras);
-
void setP2pModes(int initatorModes, int targetModes);
-
void addNfcUnlockHandler(INfcUnlockHandler unlockHandler, in int[] techList);
-
void removeNfcUnlockHandler(INfcUnlockHandler unlockHandler);
-
}
3. ScreenStateHelper
这个类主要作用是检查当前屏幕状态,原因是NFC的一些应用需要在屏灭以及锁屏的情况下也能应用(例如刷公交卡),主要的函数如下:
-
int checkScreenState() {
-
//TODO: fix deprecated api
-
if (!mPowerManager.isScreenOn()) {
-
//@paul: 依据pm提供的接口判断屏幕是否点亮
-
return SCREEN_STATE_OFF;
-
} else if (mKeyguardManager.isKeyguardLocked()) {
-
//@paul: 依据KeyguardManager判断是否在解锁状态
-
return SCREEN_STATE_ON_LOCKED;
-
} else {
-
//@paul: 上述都不是,则设备处于屏幕解锁状态
-
return SCREEN_STATE_ON_UNLOCKED;
-
}
-
}
4.NativeNfcManager
此类是各chip vendor实现,目前AOSP下包含了nxp和nci两类。下面的例子都是以nxp的接口为例,nci接口也类似。
此类的开头就有以下的信息,表示实例化该类时,先加载且只加载一次libnfc_jni.so:
-
static {
-
System.loadLibrary( "nfc_jni");
-
}
-
public NativeNfcManager(Context context, DeviceHostListener listener) {
-
mListener = listener;
-
initializeNativeStructure();
-
mContext = context;
-
}
其中initializeNativeStructure()是native函数,其定义在:
{"initializeNativeStructure", "()Z",(void *)com_android_nfc_NfcManager_init_native_struc},
继续分析:
-
static jboolean com_android_nfc_NfcManager_init_native_struc(JNIEnv *e, jobject o)
-
{
-
...
-
TRACE( "****** Init Native Structure ******");
-
-
/* Initialize native structure */
-
nat = (nfc_jni_native_data*) malloc( sizeof(struct nfc_jni_native_data));
-
...
-
-
-
/* Initialize native cached references */
-
//@paul: 定义native层和framework沟通的API
-
cached_NfcManager_notifyNdefMessageListeners = e->GetMethodID(cls,
-
"notifyNdefMessageListeners", "(Lcom/android/nfc/dhimpl/NativeNfcTag;)V");
-
-
cached_NfcManager_notifyLlcpLinkActivation = e->GetMethodID(cls,
-
"notifyLlcpLinkActivation", "(Lcom/android/nfc/dhimpl/NativeP2pDevice;)V");
-
-
cached_NfcManager_notifyLlcpLinkDeactivated = e->GetMethodID(cls,
-
"notifyLlcpLinkDeactivated", "(Lcom/android/nfc/dhimpl/NativeP2pDevice;)V");
-
-
cached_NfcManager_notifyRfFieldActivated = e->GetMethodID(cls,
-
"notifyRfFieldActivated", "()V");
-
-
cached_NfcManager_notifyRfFieldDeactivated = e->GetMethodID(cls,
-
"notifyRfFieldDeactivated", "()V");
-
-
if(nfc_jni_cache_object(e, "com/android/nfc/dhimpl/NativeNfcTag",&(nat->cached_NfcTag)) == -1)
-
{
-
ALOGD( "Native Structure initialization failed");
-
return FALSE;
-
}
-
-
if(nfc_jni_cache_object(e, "com/android/nfc/dhimpl/NativeP2pDevice",&(nat->cached_P2pDevice)) == -1)
-
{
-
ALOGD( "Native Structure initialization failed");
-
return FALSE;
-
}
-
TRACE( "****** Init Native Structure OK ******");
-
return TRUE;
-
-
}
在以其中cached_NfcManager_notifyNdefMessageListeners引用为例,该引用在nfc_jni_Discovery_notification_callback中以下列方式被调用,从而将底层的消息notify到上层APP:
-
/* Notify manager that new a tag was found */
-
e->CallVoidMethod(nat->manager, cached_NfcManager_notifyNdefMessageListeners, tag.get());
-
if(e->ExceptionCheck())
-
{
-
ALOGE( "Exception occurred");
-
kill_client(nat);
-
}
以其中enableDiscovery()函数为例,说明一下该类的基本操作流程:
-
//@paul: native接口,
-
private native void doEnableDiscovery(int techMask,
-
boolean enableLowPowerPolling,
-
boolean enableReaderMode,
-
boolean restart);
-
-
public void enableDiscovery(NfcDiscoveryParameters params, boolean restart) {
-
doEnableDiscovery(params.getTechMask(), params.shouldEnableLowPowerDiscovery(),params.shouldEnableReaderMode(), restart);
-
}
此类主要负责NFC到其他传输媒介的跳转,例如Wi-Fi/BT,只是目前AOSP只有是做BT的跳转。Wi-Fi还没有定义Spec,所以还没有这部分的代码。关于BT Handover的spec,可以参考NFC简单介绍中Spec下载章节。
后续会继续讲解Handover的流程,此部分就不做详细介绍。
5.NfcDispatcher
此类主要是收到底层Tag消息后,依据tag的类型进行内容解析和数据分发。
-
public int dispatchTag(Tag tag) {
-
...
-
-
//@paul: APP在调用setForegroundDispatch()时,会赋值下列变量
-
synchronized ( this) {
-
overrideFilters = mOverrideFilters;
-
overrideIntent = mOverrideIntent;
-
overrideTechLists = mOverrideTechLists;
-
provisioningOnly = mProvisioningOnly;
-
}
-
-
//@paul: 屏幕解锁相关流程
-
boolean screenUnlocked = false;
-
if (!provisioningOnly &&
-
mScreenStateHelper.checkScreenState() == ScreenStateHelper.SCREEN_STATE_ON_LOCKED) {
-
screenUnlocked = handleNfcUnlock(tag);
-
if (!screenUnlocked) {
-
return DISPATCH_FAIL;
-
}
-
}
-
...
-
-
//@paul: 如果前台Activity启动分发功能,则只需要处理前台分发相关工作即可
-
if (tryOverrides(dispatch, tag, message, overrideIntent, overrideFilters,
-
overrideTechLists)) {
-
return screenUnlocked ? DISPATCH_UNLOCK : DISPATCH_SUCCESS;
-
}
-
-
//@paul: 判断是否为Handover事件
-
if (mHandoverManager.tryHandover(message)) {
-
if (DBG) Log.i(TAG, "matched BT HANDOVER");
-
return screenUnlocked ? DISPATCH_UNLOCK : DISPATCH_SUCCESS;
-
}
-
-
//@paul: 判断是否为Wifi的handover
-
if (NfcWifiProtectedSetup.tryNfcWifiSetup(ndef, mContext)) {
-
if (DBG) Log.i(TAG, "matched NFC WPS TOKEN");
-
return screenUnlocked ? DISPATCH_UNLOCK : DISPATCH_SUCCESS;
-
}
-
-
//@paul: 判断是否为ACTION_NDEF_DISCOVERD
-
if (tryNdef(dispatch, message, provisioningOnly)) {
-
return screenUnlocked ? DISPATCH_UNLOCK : DISPATCH_SUCCESS;
-
}
-
//@paul: 只有在NDEF格式下,才会判断此流程
-
if (screenUnlocked) {
-
// We only allow NDEF-based mimeType matching in case of an unlock
-
return DISPATCH_UNLOCK;
-
}
-
if (provisioningOnly) {
-
// We only allow NDEF-based mimeType matching
-
return DISPATCH_FAIL;
-
}
-
-
//@paul: 判断是否为ACTION_TECH_DISCOVERD
-
if (tryTech(dispatch, tag)) {
-
return DISPATCH_SUCCESS;
-
}
-
-
//@paul: 设置intent为ACTION_TAG_DISCOVERD
-
dispatch.setTagIntent();
-
//@paul: 查询对ACTION_TAG_DISCOVERD感兴趣的activity,并尝试启动
-
if (dispatch.tryStartActivity()) {
-
if (DBG) Log.i(TAG, "matched TAG");
-
return DISPATCH_SUCCESS;
-
}
-
-
if (DBG) Log.i(TAG, "no match");
-
return DISPATCH_FAIL;
-
}
6.P2pLinkManager
此类主要包含基于LLCP连接的server,构造函数中会创建后续需要的类:
-
public P2pLinkManager(Context context, HandoverManager handoverManager, int defaultMiu,int defaultRwSize) {
-
//@paul: 创建NdefPushServer()
-
mNdefPushServer = new NdefPushServer(NDEFPUSH_SAP, mNppCallback);
-
//@paul: 创建SnepServer()
-
mDefaultSnepServer = new SnepServer(mDefaultSnepCallback, defaultMiu, defaultRwSize);
-
//@paul: 创建HandoverServer()
-
mHandoverServer = new HandoverServer(HANDOVER_SAP, handoverManager, mHandoverCallback);
-
//@paul: 创建EchoServer()
-
if (ECHOSERVER_ENABLED) {
-
mEchoServer = new EchoServer();
-
} else {
-
mEchoServer = null;
-
}
-
mPackageManager = context.getPackageManager();
-
mContext = context;
-
//@paul: 创建P2pEventManager()
-
mEventListener = new P2pEventManager(context, this);
-
mHandler = new Handler( this);
-
...
-
}
NdefPushServer:启动NPP Server,等待Client连接
SnepServer:启动NPP Server,等待Client连接
HandoverServer:启动Handover Server,等待Client连接
P2pEventManager: 启动Event Manager,用于将底层消息notify到UI或者上层APP
下面分别以SnepServer,P2pEventManager为例,简单说明一下流程(也会补充一下handle的流程)。
SnepServer的构造函数调用后,会被调用到启动函数start():
-
//@paul: 启动SNEP server
-
public void start() {
-
synchronized (SnepServer. this) {
-
if (DBG) Log.d(TAG, "start, thread = " + mServerThread);
-
if (mServerThread == null) {
-
if (DBG) Log.d(TAG, "starting new server thread");
-
mServerThread = new ServerThread();
-
//@paul: ServerThread.run()
-
mServerThread.start();
-
mServerRunning = true;
-
}
-
}
-
}
-
-
public void run() {
-
...
-
while (threadRunning) {
-
if (DBG) Log.d(TAG, "about create LLCP service socket");
-
try {
-
synchronized (SnepServer. this) {
-
//@paul: 创建llcp 服务端socket
-
//@paul: 包含创建socket,绑定并监听socket
-
mServerSocket = NfcService.getInstance().createLlcpServerSocket(mServiceSap,
-
mServiceName, mMiu, mRwSize, 1024);
-
}
-
...
-
while (threadRunning) {
-
...
-
if (DBG) Log.d(TAG, "about to accept");
-
//@paul: 阻塞等待客户端连接
-
//@paul: 一个server 端,可以有多个客户端连接
-
//@paul: 每次client 端连接都会创建新的thread
-
LlcpSocket communicationSocket = serverSocket.accept();
-
if (DBG) Log.d(TAG, "accept returned " + communicationSocket);
-
if (communicationSocket != null) {
-
int fragmentLength = (mFragmentLength == - 1) ?
-
mMiu : Math.min(mMiu, mFragmentLength);
-
//@paul: 一旦有客户端请求连接
-
new ConnectionThread(communicationSocket, fragmentLength).start();
-
}
-
...
-
}
-
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 {
-
...
-
try {
-
mServerSocket.close();
-
} catch (IOException e) {
-
// ignore
-
}
-
mServerSocket = null;
-
}
-
}
-
}
-
...
-
}
-
}
一旦有client端来连接,就会调用到ConnectionThread的run()函数:
-
ConnectionThread(LlcpSocket socket, int fragmentLength) {
-
super(TAG);
-
mSock = socket;
-
//@paul: 创建SnepMessenger 消息处理类
-
mMessager = new SnepMessenger( false, socket, fragmentLength);
-
}
-
-
-
public void run() {
-
if (DBG) Log.d(TAG, "starting connection thread");
-
try {
-
...
-
while (running) {
-
//@paul: 每次只要有消息进来,就会进入消息处理流程handleRequest
-
//@paul:后续还会说明handleRequest,此部分不多说明
-
if (!handleRequest(mMessager, mCallback)) {
-
break;
-
}
-
...
-
}
-
} catch (IOException e) {
-
...
-
}
-
...
-
}
接下来就是P2pEventManager,此类只要是将底层的消息notify给上层,在其构造函数中,最重要的信息如下:
-
public P2pEventManager(Context context, P2pEventListener.Callback callback) {
-
...
-
final int uiModeType = mContext.getResources().getConfiguration().uiMode
-
& Configuration.UI_MODE_TYPE_MASK;
-
if (uiModeType == Configuration.UI_MODE_TYPE_APPLIANCE) {
-
// "Appliances" don't intrinsically have a way of confirming this, so we
-
// don't use the UI and just autoconfirm where necessary.
-
// Don't instantiate SendUi or else we'll use memory and never reclaim it.
-
mSendUi = null;
-
} else {
-
//@paul: 创建SendUI类,实现与UI层的沟通
-
mSendUi = new SendUi(context, this);
-
}
-
}
-
public void onP2pInRange()
-
public void onP2pNfcTapRequested ()
-
public void onP2pTimeoutWaitingForLink ()
-
public void onP2pSendConfirmationRequested ()
-
public void onP2pSendComplete ()
-
public void onP2pHandoverNotSupported ()
-
public void onP2pReceiveComplete (boolean playSound)
-
public void onP2pOutOfRange ()
-
public void onSendConfirmed ()
-
public void onCanceled ()
-
public void onP2pSendDebounce ()
-
public void onP2pResumeSend ()
前面也有提到,P2pLinkManager中会实例化一个handle,那handler的作用是什么呢?这时候就需要注意到P2pLinkManager实现的方式:
-
class P2pLinkManager implements Handler.Callback, P2pEventListener.Callback {
-
...
-
}
同时发现代码中出现了handleMessage(),其内容为:
-
-
public boolean handleMessage(Message msg) {
-
switch (msg.what) {
-
case MSG_START_ECHOSERVER:
-
...
-
case MSG_STOP_ECHOSERVER:
-
...
-
case MSG_WAIT_FOR_LINK_TIMEOUT:
-
...
-
case MSG_DEBOUNCE_TIMEOUT:
-
...
-
case MSG_RECEIVE_HANDOVER:
-
...
-
case MSG_RECEIVE_COMPLETE:
-
...
-
case MSG_HANDOVER_NOT_SUPPORTED:
-
...
-
case MSG_SEND_COMPLETE:
-
...
-
}
-
return true;
-
}
我们不禁又要问,那这些message都是从哪里传递上来的呢?以MSG_SEND_COMPLETE为例,在P2pLinkManager.java中:
-
void onReceiveComplete(NdefMessage msg) {
-
// Make callbacks on UI thread
-
mHandler.obtainMessage(MSG_RECEIVE_COMPLETE, msg).sendToTarget();
-
}
7. NfceeAccessControl *
从代码流程看,只是去读取并解析/etc/nfcee_access.xml文件。此处目前还不是很懂实际的应用场景,先跳过。
8.CardEmulationManager *
此部分目前还没有详细研究,先跳过。
9.然后呢,然后发现就只有下面这一句了:
EnableDisableTask().execute(TASK_BOOT)
那我们看看这个函数做什么了?
-
-
protected Void doInBackground(Integer... params) {
-
// Sanity check mState
-
...
-
-
/* 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:
-
//@paul: 如果传入参数是enable,那就直接初始化NFC芯片等,否则
-
enableInternal();
-
break;
-
case TASK_DISABLE:
-
//@paul: 否则关闭NFC
-
disableInternal();
-
break;
-
case TASK_BOOT:
-
//@paul: 第一次流程上会进入到这里
-
Log.d(TAG, "checking on firmware download");
-
//@paul: 检查prefs中定义的PREF_AIRPLANE_OVERRIDE的值,AOSP没有定义这个值,即为false
-
boolean airplaneOverride = mPrefs.getBoolean(PREF_AIRPLANE_OVERRIDE, false);
-
//@paul:判断prefs中定义的PREF_NFC_ON,AOSP没有定义这个值,即为NFC_ON_DEFAULT
-
//@paul:依据Setting.System中设定,判断mIsAirplaneSensitive(默认true),isAirplaneModeOn(默认false)
-
if (mPrefs.getBoolean(PREF_NFC_ON, NFC_ON_DEFAULT) &&
-
(!mIsAirplaneSensitive || !isAirplaneModeOn() || airplaneOverride)) {
-
Log.d(TAG, "NFC is on. Doing normal stuff");
-
//@paul: 默认NFC打开,开始激活NFC
-
enableInternal();
-
} else {
-
Log.d(TAG, "NFC is off. Checking firmware version");
-
//@paul: 关闭状态则检查是否要更新fireware
-
mDeviceHost.checkFirmware();
-
}
-
//@paul: 更新prefs中的PREF_FIRST_BOOT值
-
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()中,你们可能着急了,这里面做什么了呢?
-
/**
-
* Enable NFC adapter functions.
-
* Does not toggle preferences.
-
*/
-
boolean enableInternal() {
-
Log.i(TAG, "Enabling NFC");
-
...
-
-
try {
-
...
-
try {
-
//@paul: 执行DH.initialize(),芯片初始化
-
if (!mDeviceHost.initialize()) {
-
Log.w(TAG, "Error enabling NFC");
-
updateState(NfcAdapter.STATE_OFF);
-
return false;
-
}
-
} finally {
-
...
-
}
-
}
-
...
-
synchronized (NfcService. this) {
-
...
-
//@paul: 依据传入值,判断启动对应服务
-
//@paul: mIsNdefPushEnabled由系统设定值确定
-
mP2pLinkManager.enableDisable(mIsNdefPushEnabled, true);
-
updateState(NfcAdapter.STATE_ON);
-
}
-
//@paul: 设置启动,完成,错误时对应的声音文件
-
initSoundPool();
-
-
/* Start polling loop */
-
//@paul: 启动NFC底层轮询
-
applyRouting( true);
-
return true;
-
}
applyRouting()之后,就启动底层的polling机制,如果底层侦测到有NFC设备靠近,就会进入对应的处理流程。
到目前为止,基本上NFC的功能都有启动,剩下的工作就是有不同的设备接近的事情,进入不同的流程进行处理。
后续会从Tag以及P2P两个方面进行系统流程的分析。
前文提到的CardEmulation 以及NFCEE_ACCESS部分会看后续学习的情况进行补充。