1. Sequence diagram of NFC initialization:
2. Code analysis:
Initialization is divided into two parts. The first part is the initialization of the server which is used by the framework, and the service is added to the Service Manager. The second part is the initialization of the NFC adapter Nfc adapter, which contains the services corresponding to the NFC protocol.
* Server initialization:
NFC's server-side code is located in packages/apps/Nfc, and also contains JNI code. NFC's server-side, like phone app, is an application that follows a service process that the system starts and always exists. Take a look at packages / apps / Nfc
Definitions in Android Manifest. XML in the directory:
<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" indicates that the application has been in existence since the system was started until the system shut down.
NfcApplication inherits from Application. When the program starts, the onCreate() method is called. The code is as follows:
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(); } }
The NfcService object is constructed in the onCreat() method. To further analyze the code in the constructor of NfcService:
public NfcService(Application nfcApplication) {
mUserId = ActivityManager.getCurrentUser(); // Gets the current userID, mainly in multi-user scenarios for user switching to update the context environment
mContext = nfcApplication;
mNfcTagService = new TagService(); //Related to Tag, TagService eventually calls methods in NativeNfcTag mNfcAdapter = new NfcAdapterService(); //Upper application calls Nfc Adapter Service indirectly through framework and binder sService = this; mScreenStateHelper = new ScreenStateHelper(mContext); //Check screen lock status ON,OFF,ON_UNLOCK mContentResolver = mContext.getContentResolver(); mDeviceHost = new NativeNfcManager(mContext, this); //Native Nfc Manager provides an interface to interact with C++ layer. The key point is that Native Nfc Manager informs Nfc Service of the status of NFC in time. mNfcUnlockManager = NfcUnlockManager.getInstance(); mHandoverDataParser = new HandoverDataParser();//Data analysis of handover boolean isNfcProvisioningEnabled = false; try { isNfcProvisioningEnabled = mContext.getResources().getBoolean( R.bool.enable_nfc_provisioning); } catch (NotFoundException e) { } //Does the device support receiving NFC data during the setup wizard phase if (isNfcProvisioningEnabled) { mInProvisionMode = Settings.Secure.getInt(mContentResolver, Settings.Global.DEVICE_PROVISIONED, 0) == 0; } else { mInProvisionMode = false; } //Receive the NFC message processing process, and finally call dispatchTag(), send the Tag message to the corresponding activity for processing. mNfcDispatcher = new NfcDispatcher(mContext, mHandoverDataParser, mInProvisionMode); //Based on PPLC, P2pLinkManager manages the transmission of P2P, mainly completes the receiving and sending of data. mP2pLinkManager = new P2pLinkManager(mContext, mHandoverDataParser, mDeviceHost.getDefaultLlcpMiu(), mDeviceHost.getDefaultLlcpRwSize()); mPrefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); mPrefsEditor = mPrefs.edit(); //Related to the security of NFC, mainly read the parse / etc/nfcee_access.xml file mNfceeAccessControl = new NfceeAccessControl(mContext); mState = NfcAdapter.STATE_OFF; //shareperference is created in NFC to save some state values related to NFC, where you can get whether NdefPush is enable d mIsNdefPushEnabled = mPrefs.getBoolean(PREF_NDEF_PUSH_ON, NDEF_PUSH_ON_DEFAULT); setBeamShareActivityState(mIsNdefPushEnabled); mIsDebugBuild = "userdebug".equals(Build.TYPE) || "eng".equals(Build.TYPE); //Power management is related to whether the NFC responds or not. 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 // Listen for various radio screen lock-in States and user switching events 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); //Detection of application installation and deletion events to display related processing applications when 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(); //Determine whether card emulation is supported 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);//Add the service to the system service with the service name "nfc" new EnableDisableTask().execute(TASK_BOOT); // do blocking boot tasks // Create threads to process TASK_BOOT mHandler.sendEmptyMessageDelayed(MSG_UPDATE_STATS, STATS_UPDATE_INTERVAL_MS); }
In the case of TASK_BOOT in Enable DisableTask, relevant processing is performed according to the current state of NFC, that is, the NFC function is turned on or off. When the NFC function is turned on, enableInternal() is executed, which can be referred to as the process of NFC opening:
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;
The service in NfsService will be described in detail in the core class.
* Initialization of NFC adapter Nfc adapter:
System Service Registry maintains all registered services, including NfcManager, which is called indirectly to NfcAdapter Service through NfcAdapter.getNfcAdapter(context) and NfcAdapter by service name "nfc".
Because NfcAdapterService is an internal class of NfcService, it can be manipulated to various instantiated objects in NfcService.
Specific analysis of the code flow:
SystemService Registry is called in ContextImpl, which is not specified. Take a look at the registration process of NfcManager
In the private constructor of System Service Registry, it was found that the NfcManager was created and registered with the service.
registerService(Context.NFC_SERVICE, NfcManager.class,
new CachedServiceFetcher() {
@Override
public NfcManager createService(ContextImpl ctx) {
return new NfcManager(ctx);
}});
Then continue to analyze the code processing in 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); //Calling getNfcAdapter method class in NfcAdapter to get 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; }
}
How to get NfcAdapter in NfcAdapter, where getNfcAdapter() is a static method and can be operated directly by class name:
public static synchronized NfcAdapter getNfcAdapter(Context context) { if (!sIsInitialized) { //Determine whether initialization has been done, and if not, get the corresponding status and services sHasNfcFeature = hasNfcFeature(); //Determine whether NFC functionality is supported boolean hasHceFeature = hasNfcHceFeature(); //Whether to support the function of nfc analog card /* is this device meant to have NFC */ if (!sHasNfcFeature && !hasHceFeature) { //Exceptions are thrown if NFC functionality is not supported Log.v(TAG, "this device does not have NFC support"); throw new UnsupportedOperationException(); } sService = getServiceInterface(); //Get the NFC service, as you can see in the following function instance, by the service name'nfc' if (sService == null) { Log.e(TAG, "could not retrieve NFC service"); throw new UnsupportedOperationException(); } if (sHasNfcFeature) { //Get TagService if NFC functionality is supported try { sTagService = sService.getNfcTagInterface(); } catch (RemoteException e) { Log.e(TAG, "could not retrieve NFC Tag service"); throw new UnsupportedOperationException(); } } if (hasHceFeature) { //Determine whether the analog card function is supported or not, and if so, get the analog card service. 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"); //Get NfcService by name if (b == null) { return null; } return INfcAdapter.Stub.asInterface(b); }