[Android7.0]NFC初始化的流程分析
1、NFC初始化的時序圖:
2、程式碼分析:
初始化分兩部分,第一供應framework使用的服務端初始化,並將服務新增到ServiceManager中,第二是初始化NFC介面卡NfcAdapter,其中就包含何種對應NFC協議的服務。
* 服務端的初始化:
NFC的服務端程式碼位於packages/apps/Nfc中,並且還包含了JNI程式碼,NFC的服務端類似phone app是一個應用程式,跟隨系統啟動並一直存在的一個服務程序。 可以看一下packages/apps/Nfc
目錄中的AndroidManifest.xml中的定義:
<application android: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:usesCleartextTraffic="false"
其中android:persistent=”true”,表明該應用在系統啟動之後直到系統關機一直是存在的。
NfcApplication 繼承於Application,當程式啟動的時候,呼叫onCreate()方法,程式碼如下:
public class NfcApplication extends Application {
…..
@Override
public void onCreate() {
super.onCreate();
boolean isMainProcess = false; // We start a service in a separate process to do // handover transfer. We don't want to instantiate an NfcService // object in those cases, hence check the name of the process // to determine whether we're the main NFC service, or the // handover process ActivityManager am = (ActivityManager)this.getSystemService(ACTIVITY_SERVICE); List processes = am.getRunningAppProcesses(); Iterator i = processes.iterator(); while (i.hasNext()) { RunningAppProcessInfo appInfo = (RunningAppProcessInfo)(i.next()); if (appInfo.pid == Process.myPid()) { isMainProcess = (NFC_PROCESS.equals(appInfo.processName)); break; } } if (UserHandle.myUserId() == 0 && isMainProcess) { mNfcService = new NfcService(this); ThreadedRenderer.enableForegroundTrimming(); } }
在onCreat()的方法中構建了NfcService物件。進一步的去分析一下NfcService的建構函式中的程式碼:
public NfcService(Application nfcApplication) {
mUserId = ActivityManager.getCurrentUser(); //獲取當前userID,主要在多使用者場景下進行使用者切換到時候來更新上下文環境
mContext = nfcApplication;
mNfcTagService = new TagService(); //與Tag相關,TagService最終會呼叫到NativeNfcTag中的方法 mNfcAdapter = new NfcAdapterService(); //上層應用通過framework,間接通過binder呼叫到NfcAdapterService sService = this; mScreenStateHelper = new ScreenStateHelper(mContext); //檢查螢幕的鎖屏狀態ON,OFF,ON_UNLOCK mContentResolver = mContext.getContentResolver(); mDeviceHost = new NativeNfcManager(mContext, this); //NativeNfcManager提供和C++層進行互動的介面,最關鍵的一點NativeNfcManager將NFC的狀態及時通知NfcService mNfcUnlockManager = NfcUnlockManager.getInstance(); mHandoverDataParser = new HandoverDataParser();//handover的資料分析 boolean isNfcProvisioningEnabled = false; try { isNfcProvisioningEnabled = mContext.getResources().getBoolean( R.bool.enable_nfc_provisioning); } catch (NotFoundException e) { } //裝置是否在setup wizard階段支援接收NFC 資料 if (isNfcProvisioningEnabled) { mInProvisionMode = Settings.Secure.getInt(mContentResolver, Settings.Global.DEVICE_PROVISIONED, 0) == 0; } else { mInProvisionMode = false; } //收到NFC 訊息處理流程, 最終呼叫到dispatchTag(),將Tag訊息傳送給對應的activity進行處理 mNfcDispatcher = new NfcDispatcher(mContext, mHandoverDataParser, mInProvisionMode); //P2pLinkManager基於PPLC,對P2P的傳輸進行管理,主要完成資料的接收和傳送 mP2pLinkManager = new P2pLinkManager(mContext, mHandoverDataParser, mDeviceHost.getDefaultLlcpMiu(), mDeviceHost.getDefaultLlcpRwSize()); mPrefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); mPrefsEditor = mPrefs.edit(); //和NFC的security相關,主要是讀取解析/etc/nfcee_access.xml檔案 mNfceeAccessControl = new NfceeAccessControl(mContext); mState = NfcAdapter.STATE_OFF; //在nfc中會建立shareperference來儲存NFC相關的一些狀態值,在此處獲取NdefPush是否enable mIsNdefPushEnabled = mPrefs.getBoolean(PREF_NDEF_PUSH_ON, NDEF_PUSH_ON_DEFAULT); setBeamShareActivityState(mIsNdefPushEnabled); mIsDebugBuild = "userdebug".equals(Build.TYPE) || "eng".equals(Build.TYPE); //電源管理相關,目的是和NFC是否響應相關 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); mRoutingWakeLock = mPowerManager.newWakeLock( PowerManager.PARTIAL_WAKE_LOCK, "NfcService:mRoutingWakeLock"); mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE); mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); mScreenState = mScreenStateHelper.checkScreenState(); mNumTagsDetected = new AtomicInteger(); mNumP2pDetected = new AtomicInteger(); mNumHceDetected = new AtomicInteger(); // Intents for all users //監聽各種廣播螢幕鎖頻狀態,以及使用者切換事件 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); 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); //檢測應用安裝和刪除的事件,為了在dispatchTag的時候,顯示相關處理的應用 ownerFilter = new IntentFilter(); ownerFilter.addAction(Intent.ACTION_PACKAGE_ADDED); ownerFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); ownerFilter.addDataScheme("package"); mContext.registerReceiver(mOwnerReceiver, ownerFilter); IntentFilter policyFilter = new IntentFilter(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED); mContext.registerReceiverAsUser(mPolicyReceiver, UserHandle.ALL, policyFilter, null, null); updatePackageCache(); //判斷是否支援card emulation的功能 PackageManager pm = mContext.getPackageManager(); mIsHceCapable = pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION) || pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION_NFCF); mIsHceFCapable = pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION_NFCF); if (mIsHceCapable) { mCardEmulationManager = new CardEmulationManager(mContext); } mForegroundUtils = ForegroundUtils.getInstance(); // Make sure this is only called when object construction is complete. ServiceManager.addService(SERVICE_NAME, mNfcAdapter);//將服務新增到系統服務中,服務名稱為“nfc” new EnableDisableTask().execute(TASK_BOOT); // do blocking boot tasks //建立執行緒來處理TASK_BOOT mHandler.sendEmptyMessageDelayed(MSG_UPDATE_STATS, STATS_UPDATE_INTERVAL_MS); }
在EnableDisableTask針對TASK_BOOT這個case,會根據當前NFC的狀態,即NFC功能開啟或者關閉,來進行相關的處理。當NFC功能開啟就會執行enableInternal(),這個可以參考NFC開啟的流程:
case TASK_BOOT:
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;
關於NfsService中的服務,在核心類中會進行詳細的說明。
* NFC介面卡NfcAdapter的初始化:
SystemServiceRegistry來維護註冊進去的所有服務,其中就包含了NfcManager,NfcManager中通過NfcAdapter.getNfcAdapter(context);而在NfcAdapter中通過服務名稱”nfc”,間接呼叫到NfcAdapterService。
由於NfcAdapterService為NfcService的內部類,從而可以操作到NfcService中的各個例項化物件。
具體分析一下程式碼流程:
其中SystemServiceRegistry在ContextImpl中進行呼叫,就不具體說明了。主要看一下NfcManager的註冊過程
在SystemServiceRegistry的私有建構函式中,發現建立了NfcManager,並將其註冊到服務中去了。
registerService(Context.NFC_SERVICE, NfcManager.class,
new CachedServiceFetcher() {
@Override
public NfcManager createService(ContextImpl ctx) {
return new NfcManager(ctx);
}});
接著繼續分析NfcManager中的程式碼處理:
public NfcManager(Context context) {
NfcAdapter adapter;
context = context.getApplicationContext();
if (context == null) {
throw new IllegalArgumentException(
"context not associated with any application (using a mock context?)");
}
try {
adapter = NfcAdapter.getNfcAdapter(context); //呼叫NfcAdapter中的getNfcAdapter方法類獲取NfcAdapter
} catch (UnsupportedOperationException e) {
adapter = null;
}
mAdapter = adapter;
}
/**
* Get the default NFC Adapter for this device.
*
* @return the default NFC Adapter
*/
public NfcAdapter getDefaultAdapter() {
return mAdapter;
}
}
NfcAdapter中如何獲取NfcAdapter的,其中getNfcAdapter()為靜態方法,可以直接通過類名進行操作:
public static synchronized NfcAdapter getNfcAdapter(Context context) {
if (!sIsInitialized) { //判斷是否已經進行了初始化,如果沒有就獲取對應的狀態和服務
sHasNfcFeature = hasNfcFeature(); //判斷是否支援NFC功能
boolean hasHceFeature = hasNfcHceFeature(); //是否支援nfc 模擬卡的功能
/* is this device meant to have NFC */
if (!sHasNfcFeature && !hasHceFeature) { //如果不支援NFC功能就會丟擲異常
Log.v(TAG, "this device does not have NFC support");
throw new UnsupportedOperationException();
}
sService = getServiceInterface(); //獲取NFC服務,在下面的函式例項中可以看到通過服務名稱'nfc'來獲取
if (sService == null) {
Log.e(TAG, "could not retrieve NFC service");
throw new UnsupportedOperationException();
}
if (sHasNfcFeature) { //如果支援NFC功能就獲取TagService
try {
sTagService = sService.getNfcTagInterface();
} catch (RemoteException e) {
Log.e(TAG, "could not retrieve NFC Tag service");
throw new UnsupportedOperationException();
}
}
if (hasHceFeature) { //判斷是否支援模擬卡功能,如果支援就獲取模擬卡服務
try {
sNfcFCardEmulationService = sService.getNfcFCardEmulationInterface();
} catch (RemoteException e) {
Log.e(TAG, "could not retrieve NFC-F card emulation service");
throw new UnsupportedOperationException();
}
try {
sCardEmulationService = sService.getNfcCardEmulationInterface();
} catch (RemoteException e) {
Log.e(TAG, "could not retrieve card emulation service");
throw new UnsupportedOperationException();
}
}
sIsInitialized = true;
}
if (context == null) {
if (sNullContextNfcAdapter == null) {
sNullContextNfcAdapter = new NfcAdapter(null);
}
return sNullContextNfcAdapter;
}
NfcAdapter adapter = sNfcAdapters.get(context);
if (adapter == null) {
adapter = new NfcAdapter(context);
sNfcAdapters.put(context, adapter);
}
return adapter;
}
/** get handle to NFC service interface */
private static INfcAdapter getServiceInterface() {
/* get a handle to NFC service */
IBinder b = ServiceManager.getService("nfc"); //通過名稱來獲取NfcService
if (b == null) {
return null;
}
return INfcAdapter.Stub.asInterface(b);
}