iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 15
1
  • Guide :
    • 介紹
    • Service
    • Adapter
    • Handover
    • Kernel

初始化流程解析

初始化分程兩大部份:

  1. NfcService 初始化,並將它加入 ServiceManager。
  2. NfcAdapter 初始化。

因為函式呼叫通常就是跳來跳去的,所以參考下圖會更清楚一些:

https://ithelp.ithome.com.tw/upload/images/20190930/201205153GPJ8b88h7.jpg


NfcService

NFC 的服務端位於源碼的 packages/apps/Nfc 位置,
並且包含了 JNI 的部份,
串接到 library 和 framework 層應用。
它有點像是 phone app 那樣,是一個應用程序,
跟著 Android 開機啟動後一直存在在背景。

這時可以稍微看一下 AndroidManifest.xml 內容,
裡面宣告了一些需要用到的權限 (permission) 和意圖 (intent):

 <!-- 權限的宣告 -->
 21     <uses-permission android:name="android.permission.BLUETOOTH" />
 22     <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
 23     <uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" />
 24     <uses-permission android:name="android.permission.NFC" />
 25     <uses-permission android:name="android.permission.NFC_UNLOCK" />
... ...
 <!-- 主要的應用服務宣告 -->
 62     <application android:name=".NfcApplication"
 63                  android:icon="@drawable/icon"
 64                  android:label="@string/app_name"
 65                  android:theme="@android:style/Theme.Material.Light"
 66                  android:persistent="true"
 67                  android:persistentWhenFeatureAvailable="android.hardware.nfc.any"
 68                  android:backupAgent="com.android.nfc.NfcBackupAgent"
 69                  android:killAfterRestore="false"
 70                  android:usesCleartextTraffic="false"
 71                  android:supportsRtl="true"
 72                  android:hardwareAccelerated="false"
 73     >
... ... 
 <!-- 服務的宣告 -->
143         <service android:name=".beam.BeamSendService"
144             android:process=":beam"
145         />               
146         <service android:name=".beam.BeamReceiveService"
147             android:process=":beam"
148         />
... ...
 <!-- 意圖的宣告 -->
150         <receiver android:name=".NfcBootCompletedReceiver">
151             <intent-filter>
152                 <action android:name="android.intent.action.BOOT_COMPLETED" />
153             </intent-filter>
154         </receiver>

其中 android:persistent=”true”
表明該應用在系統啟動之後直到系統關機一直是存在的。

再看一下應用程序的起始點 ./src/com/android/nfc/NfcApplication.java
裡面的 onCreate() 函數,其實很短:

 41     @Override                         
 42     public void onCreate() {          
 43         super.onCreate();             
 44         PackageManager pm = getApplicationContext().getPackageManager();
 45         if (!pm.hasSystemFeature(PackageManager.FEATURE_NFC_ANY)) {
 46                 return;               
 47         }                             
 48          
 49         boolean isMainProcess = false;
 50         // We start a service in a separate process to do
 51         // handover transfer. We don't want to instantiate an NfcService
 52         // object in those cases, hence check the name of the process
 53         // to determine whether we're the main NFC service, or the
 54         // handover process
 55         ActivityManager am = (ActivityManager)this.getSystemService(ACTIVITY_SERVICE);
 56         List processes = am.getRunningAppProcesses();
 57         Iterator i = processes.iterator();
 58         while (i.hasNext()) {
 59             RunningAppProcessInfo appInfo = (RunningAppProcessInfo)(i.next());
 60             if (appInfo.pid == Process.myPid()) {      
 61                 isMainProcess =  (NFC_PROCESS.equals(appInfo.processName)); 
 62                 break;
 63             }
 64         }
 65         if (UserHandle.myUserId() == 0 && isMainProcess) {
 66             mNfcService = new NfcService(this);        
 67             ThreadedRenderer.enableForegroundTrimming();
 68         }
 69     }    
 70 }

我們可以看到這段分成兩大部份:
第一部份在註解講得非常清楚,
總之是它啟動了一個分支的服務叫 com.android.nfc:handover
主要負責一些藍芽耳機、鍵盤、滑鼠這類外設 (peripheral) 的資料傳輸和移轉;
還有一些容量較大的檔案透過 Android Beam 也是用這個服務,
這樣它就可以和 NFC 主服務切割開來。

第二部份就是先確定自己是主服務之後,
執行 new NfcService(this) 後宣告了一個 NfcService 對象,
再來看一下 ./src/com/android/nfc/NfcService.java 內容,
說明都在註解中:

 374     public NfcService(Application nfcApplication) {
             //獲取當前userID,主要在多用戶場景下進行用戶切換到時候來更新上下文環境
 375         mUserId = ActivityManager.getCurrentUser(); 
 376         mContext = nfcApplication;
 377
						 //與Tag相關,TagService 最终會調用到NativeNfcTag中的方法
 378         mNfcTagService = new TagService(); 
             //上層應用通過framework,間接通過binder調用到NfcAdapterService
 379         mNfcAdapter = new NfcAdapterService(); 
 380         Log.i(TAG, "Starting NFC service"); //開始囉!
 381                       
 382         sService = this;
 383 
	           //檢查屏幕的鎖屏狀態 (ON/OFF/ON_UNLOCK)
 384         mScreenStateHelper = new ScreenStateHelper(mContext); 
 385         mContentResolver = mContext.getContentResolver();
             //NativeNfcManager提供和C++層進行交互的接口,最關鍵的一點NativeNfcManager將NFC的狀態及時通知NfcService
 386         mDeviceHost = new NativeNfcManager(mContext, this); 
 387                 
 388         mNfcUnlockManager = NfcUnlockManager.getInstance();
 389         
             //handover的數據分析
 390         mHandoverDataParser = new HandoverDataParser(); 
 391         boolean isNfcProvisioningEnabled = false; 
 392         try {   
                 //宣告在res/values/provisioning.xml裡面預設是true
 393             isNfcProvisioningEnabled = mContext.getResources().getBoolean(
 394                     R.bool.enable_nfc_provisioning); 
 395         } catch (NotFoundException e) {
 396         }       
 397         //看要支援NFC哪幾種Type,通常就是看模組支援
 398         try { 
                 //宣告在res/values/live_cases.xml裡面預設是true
 399             mIsLiveCaseEnabled = mContext.getResources().getBoolean(R.bool.enable_live_cases); 
 400         } catch (NotFoundException e) {
 401             mIsLiveCaseEnabled = false;
 402         }
 403          
 404         mLiveCaseTechnology = 0;
 405         String[] liveCaseTechList;
 406         try {
                 // 宣告在res/values/live_cases.xml裡面預設只有TypeA
 407             liveCaseTechList = mContext.getResources().getStringArray(R.array.live_case_tag_types); 
 408             for (int i=0; i < liveCaseTechList.length; i++) {
 409                 if (liveCaseTechList[i].equals("TypeA")) {
 410                     mLiveCaseTechnology |= NFC_POLL_A;
 411                 } else if (liveCaseTechList[i].equals("TypeB")) {
 412                     mLiveCaseTechnology |= NFC_POLL_B;
 413                 } else if (liveCaseTechList[i].equals("TypeF")) {
 414                     mLiveCaseTechnology |= NFC_POLL_F;
 415                 } else if (liveCaseTechList[i].equals("TypeV")) {
 416                     mLiveCaseTechnology |= NFC_POLL_V;
 417                 }
 418             }
 419         } catch (NotFoundException e) {
 420             mLiveCaseTechnology = 0;
 421         }
 422         //設備是否在setup wizard階段支持接收NFC數據
 423         if (isNfcProvisioningEnabled) {
                 //官網說明連結:[Settings.Global#DEVICE_PROVISIONED](https://developer.android.com/reference/android/provider/Settings.Global#DEVICE_PROVISIONED)
 424             mInProvisionMode = Settings.Secure.getInt(mContentResolver,
 425                     Settings.Global.DEVICE_PROVISIONED, 0) == 0; 
 426         } else {
 427             mInProvisionMode = false;
 428         }
 429         //收到NFC消息處理流程, 最終調用到dispatchTag(),將Tag消息發送給對應的activity進行處理
 430         mNfcDispatcher = new NfcDispatcher(mContext, mHandoverDataParser, mInProvisionMode,
 431                 mIsLiveCaseEnabled);
						 //P2pLinkManager基於PPLC,對P2P的傳輸進行管理,主要完成數據的接收和發送
 432         mP2pLinkManager = new P2pLinkManager(mContext, mHandoverDataParser,
 433                 mDeviceHost.getDefaultLlcpMiu(), mDeviceHost.getDefaultLlcpRwSize());
 434         
 435         mPrefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE);
 436         mPrefsEditor = mPrefs.edit();
 437         
 438         mState = NfcAdapter.STATE_OFF;
             //在nfc中會創建shareperference來保存NFC相關的一些狀態值,在此處獲取NdefPush是否enable
 439         mIsNdefPushEnabled = mPrefs.getBoolean(PREF_NDEF_PUSH_ON, NDEF_PUSH_ON_DEFAULT);
 440         enforceBeamShareActivityPolicy(mContext, new UserHandle(mUserId));
 441         
 442         mIsDebugBuild = "userdebug".equals(Build.TYPE) || "eng".equals(Build.TYPE);
 443         
             //電源管理相關,目的是和NFC是否響應相關
 444         mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
 445         
 446         mRoutingWakeLock = mPowerManager.newWakeLock(
 447                 PowerManager.PARTIAL_WAKE_LOCK, "NfcService:mRoutingWakeLock");
 448         
 449         mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
 450         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
 451         mVibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
 452         mVibrationEffect = VibrationEffect.createOneShot(200, VibrationEffect.DEFAULT_AMPLITUDE);
 453         
 454         mScreenState = mScreenStateHelper.checkScreenState();
 455         
 456         mNumTagsDetected = new AtomicInteger();
 457         mNumP2pDetected = new AtomicInteger();
 458         mNumHceDetected = new AtomicInteger();
 459         
 460         mBackupManager = new BackupManager(mContext);
 461         
             //監聽各種廣播屏幕鎖頻狀態,以及用戶切換事件
 462         // Intents for all users
 463         IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
 464         filter.addAction(Intent.ACTION_SCREEN_ON);
 465         filter.addAction(Intent.ACTION_USER_PRESENT);
 466         filter.addAction(Intent.ACTION_USER_SWITCHED);
 467         mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, null);
 468 
 469         IntentFilter ownerFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
 470         ownerFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
 471         ownerFilter.addAction(Intent.ACTION_SHUTDOWN);
 472         mContext.registerReceiver(mOwnerReceiver, ownerFilter);
 473      
             //檢測應用安裝和刪除的事件,為了在dispatchTag的時候,顯示相關處理的應用
 474         ownerFilter = new IntentFilter();
 475         ownerFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
 476         ownerFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
 477         ownerFilter.addDataScheme("package");
 478         mContext.registerReceiver(mOwnerReceiver, ownerFilter);
 479      
 480         IntentFilter policyFilter = new IntentFilter(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
 481         mContext.registerReceiverAsUser(mPolicyReceiver, UserHandle.ALL, policyFilter, null, null);
 482      
 483         updatePackageCache();
 484      
             //判斷是否支持card emulation的功能
 485         PackageManager pm = mContext.getPackageManager();
 486         mIsHceCapable =
 487                 pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION) ||
 488                 pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION_NFCF);
 489         mIsHceFCapable =
 490                 pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION_NFCF);
 491         if (mIsHceCapable) {
 492             mCardEmulationManager = new CardEmulationManager(mContext);
 493         }
 494         mForegroundUtils = ForegroundUtils.getInstance();
 495      
             //將服務添加到系統服務中,SERVICE_NAME 服務名稱為 “nfc”
 496         // Make sure this is only called when object construction is complete.
 497         ServiceManager.addService(SERVICE_NAME, mNfcAdapter);
 498      
             //創建線程來處理TASK_BOOT
 499         new EnableDisableTask().execute(TASK_BOOT);  // do blocking boot tasks
 500      
 501         mHandler.sendEmptyMessageDelayed(MSG_UPDATE_STATS, STATS_UPDATE_INTERVAL_MS);
 502      
 503         IVrManager mVrManager = IVrManager.Stub.asInterface(ServiceManager.getService(
 504                 mContext.VR_SERVICE));
 505         if (mVrManager != null) {
 506             try {
 507                 mVrManager.registerListener(mVrStateCallbacks);
 508                 mIsVrModeEnabled = mVrManager.getVrModeState();
 509             } catch (RemoteException e) {
 510                 Log.e(TAG, "Failed to register VR mode state listener: " + e);
 511             }      
 512         }
 513         mSEService = ISecureElementService.Stub.asInterface(ServiceManager.getService(
 514                 Context.SECURE_ELEMENT_SERVICE));
 515     }

EnableDisableTask 針對 TASK_BOOT 這個 case,
會根據當前 NFC 的狀態,即 NFC 功能開啟或者關閉,來進行相關的處理。
當 NFC 功能開啟就會執行 enableInternal()
第一次開機時則會執行 factoryReset()
這個可以參考 ./src/com/android/nfc/NfcService.java 中 NFC 開啟的流程:

 613                 case TASK_BOOT:     
 614                     if (mPrefs.getBoolean(PREF_FIRST_BOOT, true)) {
 615                         Log.i(TAG, "First Boot");      
 616                         mPrefsEditor.putBoolean(PREF_FIRST_BOOT, false);
 617                         mPrefsEditor.apply();
 618                         mDeviceHost.factoryReset();    
 619                     }    
 620                     Log.d(TAG, "checking on firmware download");
 621                     if (mPrefs.getBoolean(PREF_NFC_ON, NFC_ON_DEFAULT)) {
 622                         Log.d(TAG, "NFC is on. Doing normal stuff");
 623                         enableInternal();              
 624                     } else {
 625                         Log.d(TAG, "NFC is off.  Checking firmware version");
 626                         mDeviceHost.checkFirmware();   
 627                     }    
 628                     SystemProperties.set("nfc.initialized", "true");
 629                     break;

好的!那第二部份 NfcAdapter 相關的內容就在下篇做詳細介紹。


上一篇
[Day-14] Android Pie NFC (1) 介紹
下一篇
[Day-16] Android Pie NFC (3) Adapter
系列文
Android Pie 底層開發學習心得30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
wig5566
iT邦新手 5 級 ‧ 2022-05-13 00:40:21

很受用的文章 請問你service trace function的圖是怎麼做的? 另外有什麼方便的trace tool嗎 這樣子一目了然 感謝

我要留言

立即登入留言