本文主要是介绍[NFC]NFC启动流程2,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
正式进入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()函数:
- @Override
- 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。
- @Override
- 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);
- @Override
- 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;
- }
- }
- }
- @Override
- 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);
- }
- @Override
- 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(),其内容为:
- @Override
- 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)
那我们看看这个函数做什么了?
- @Override
- 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部分会看后续学习的情况进行补充。
这篇关于[NFC]NFC启动流程2的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!