1. 程式人生 > >[Android7.0]NFC初始化的流程分析

[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);
}