Android5.0 Telephony框架初步分析--telecomm
3.2???Telecomm關鍵類初始化和相互關系
?
3.2.1??????????Telecomm簡述
Android5.0在Telephony的變化又比較大,增加了一個Telecomm模塊,它位于界面應用如InCallUI和Phone框架之間,其具體的設計意圖尚不明確,從代碼分析上來看,流程比原來的架構復雜很多,可能是想把Phone進程獨立得更開一些,類似于RIL進程,給應用提供一個扁平的Phone接口,不希望像以前一樣,呼叫流程在Phone進程和應用進程的縱深過大,引起函數的耦合性太大,有些相同的函數會在不同的流程執行在不同的進程里面。
其改變前后的關系可用下面的圖來簡述:
?
之前函數的調用流程在不同進程間的接口不夠平滑,現在添加新的Telecomm層后,整個軟件框架就比較有序和易于管理。
?
?
對于telephony相關的部分,從5.0和4.4的代碼比較來看,
1)在framework下面,5.0新增了telecomm和ims部分的代碼,截圖如下,
?
?
結合后面的代碼分析,我們知道在framework部分的telecomm代碼的作用是承上啟下的關系,它通過aidl接口,一方面和Phone進行交互,這一層是以InCallService、ConnectionService為代表,它的相關部分會運行在Phone進程;另一方面,和TelecommApp進程下的服務如TelecomService通信,這一層以TelecomManager等為代表,但他們往往運行在應用進程里面。
?
2)在Package目錄下,5.0的應用部分InCallUI下沒有了manifest文件,Service目錄則多了MMS、Telecomm目錄,MMS部分為短彩信增加了新的服務流程,telecomm部分則添加了一些關鍵文件,如作為進程載體的TelecomApp.java文件,作為服務載體的TelecomServiceImpl.java,還有CallsManager、CallActivity等文件,這些文件的關系和作用將在后面逐步分解。。
?
?
?
?
?
3.2.2??????????Phone
?
新增加的Phone.java在?(frameworks\base\telecomm\java\android\telecom)目錄下,其功能是“A unified virtual device providing a means of voice (and other) communication on a device.”,即作為一個虛擬設備提供通信服務。其類型如下,
???????????public final class Phone {
它的方法的實現主要依賴3個輔助類,InCallAdapter、Listener、Call,即呼叫適配器、監聽器、控制器(?),后續展開分析。
?
對于Phone的初始化,我們可以通過其方法的調用關系找到,例如查找internalAddCall,我們就會發現調用者為InCallService,其中mPhone即為Phone的實例,
case MSG_ADD_CALL:
mPhone.internalAddCall((ParcelableCall) msg.obj);
?
在InCallService里,當收到MSG_SET_IN_CALL_ADAPTER消息時,會創建一個Phone實例,同時也順帶創建了一個InCallAdapter實例,
????????????????case MSG_SET_IN_CALL_ADAPTER:
????????????????????mPhone = new Phone(new InCallAdapter((IInCallAdapter) msg.obj));
????????????????????onPhoneCreated(mPhone);
????????????????????break;??????????
?
MSG_SET_IN_CALL_ADAPTER消息是setInCallAdapter發出的,它是在InCallService里實現的AIDL接口類的服務端方法,
????private final class InCallServiceBinder extends IInCallService.Stub {
????????@Override
????????public void setInCallAdapter(IInCallAdapter inCallAdapter) {
????????????mHandler.obtainMessage(MSG_SET_IN_CALL_ADAPTER, inCallAdapter).sendToTarget();
????????}??????????
?
根據我們對service的了解,它在service類創建時創建binder,在service的onbind()方法里將binder實例傳入,執行客戶端的ServiceConnection的onServiceConnected方法,所以在客戶端,onConnected被執行,之后就是客戶端InCallController里的setInCallAdapter被調用,再間接調用前面提到的服務端的setInCallAdapter。
private class InCallServiceConnection implements ServiceConnection {
????????/** {@inheritDoc} */
????????@Override public void?onServiceConnected(ComponentName name, IBinder service) {
????????????Log.d(this, "onServiceConnected: %s", name);
????????????onConnected(name, service);
????????}?
?
????private void?onConnected(ComponentName componentName, IBinder service) {
????????ThreadUtil.checkOnMainThread();
?
????????Log.i(this, "onConnected to %s", componentName);
?
????????IInCallService inCallService = IInCallService.Stub.asInterface(service);
?
????????try {
????????????inCallService.setInCallAdapter(new InCallAdapter(CallsManager.getInstance(),
????????????????????mCallIdMapper));
????????????mInCallServices.put(componentName, inCallService);
????????} catch (RemoteException e) {
????????????Log.e(this, e, "Failed to set the in-call adapter.");
????????????return;
????????}
?
所以可以看出,Phone的實例就是在InCallService服務啟動過程中創建的。
?
?
3.2.3??????????InCallController
?
?
?
前面提到的binder的客戶端InCallController位于(packages\services\telecomm\src \com\android\server\telecom)目錄,根據manifest文件,它運行在TelecomApp這個應用里,這是一個的5.0新進程。又根據android:persistent="true"這個屬性我們知道,TelecomApp是開機自啟動的。
?
InCallController是在CallsManager的構造函數里創建的,CallsManager又是在TelecomApp的onCreate方法里面創建的,
????public void onCreate() {
????????super.onCreate();
?
????????if (UserHandle.myUserId() == UserHandle.USER_OWNER) {
????????????// Note: This style of initialization mimics what will be performed once Telecom is
????????????// moved
????????????// to run in the system service. The emphasis is on ensuring that initialization of all
????????????// telecom classes happens in one place without relying on Singleton initialization.
????????????mMissedCallNotifier = new MissedCallNotifier(this);
????????????mPhoneAccountRegistrar = new PhoneAccountRegistrar(this);
?
????????????mCallsManager = new?CallsManager(this, mMissedCallNotifier, mPhoneAccountRegistrar);
????????????CallsManager.initialize(mCallsManager);
?
????????????mTelecomService = new TelecomServiceImpl(mMissedCallNotifier, mPhoneAccountRegistrar,
????????????????????mCallsManager, this);
????????????ServiceManager.addService(Context.TELECOM_SERVICE, mTelecomService);
?
????????????// Start the BluetoothPhoneService
????????????BluetoothPhoneService.start(this);
????????}
????}??????????
?
所以,TelecomApp進程的啟動過程中,創建了InCallController和CallsManager兩個實例,這兩個類實例相互關聯。
?
?
3.2.4??????????TelecomService
?
實際上,并不存在TelecomService這個名字的文件或類名,但存在一個這樣的服務。
?
還是在TelecomApp的onCreate方法里(如上),創建了一個TelecomServiceImpl類實例,它對應于TelecomService服務的AIDL服務端,它就是以類實例為服務端,并不像service里面bind的binder接口,并且,它被作為一個服務添加到serviceManager里面。
mTelecomService = new TelecomServiceImpl(mMissedCallNotifier, mPhoneAccountRegistrar,
????????????????????mCallsManager, this);
ServiceManager.addService(Context.TELECOM_SERVICE, mTelecomService);
?
…
public class TelecomServiceImpl extends ITelecomService.Stub {??????????
TelecomServiceImpl依賴CallsManager、PhoneAccountRegistrar、MissedCallNotifier這幾個類完成相應的功能。
?
TelecomService的客戶端是TelecomManager,它通過getTelecomService獲取到服務端接口,然后通過這個接口使用服務端的遠程接口,
?????private ITelecomService getTelecomService() {
????????return ITelecomService.Stub.asInterface(ServiceManager.getService(Context.TELECOM_SERVICE));
????}
?
?
3.2.5??????????TelecomManager
?
TelecomManager在framework的android.telecom包里面,它在ContextImpl被創建,并加入到注冊列表里,屬于系統級的服務,
????????registerService(TELECOM_SERVICE, new ServiceFetcher() {
????????????????public Object createService(ContextImpl ctx) {
????????????????????return new TelecomManager(ctx.getOuterContext());
????????????????}});
…
?
應用要獲取其實例,可以通過其from方法,也可以直接通過context.getSystemService(Context.TELECOM_SERVICE)這個語句來獲取。
?
TelecomManager的功能則主要是對TelecomService提供的遠程接口的封裝,然后提供給應用使用,例如對于showInCallScreen方法,在TelecomServiceImpl提供服務端的遠程方法,TelecomManager提供客戶端訪問接口,DialpadFragment等應用組件使用這個接口,
?TelecomServiceImpl.java (packages\services\telecomm\src\com\android\server\telecom):????public void showInCallScreen(boolean showDialpad)
?
TelecomManager.java (frameworks\base\telecomm\java\android\telecom):????public void showInCallScreen(boolean showDialpad)
?
DialpadFragment.java (packages\apps\dialer\src\com\android\dialer\dialpad):????????getTelecomManager().showInCallScreen(showDialpad);
DialtactsActivity.java (packages\apps\dialer\src\com\android\dialer):????????????getTelecomManager().showInCallScreen(false);
?
雖然TelecomServiceImpl是在packages目錄下,TelecomManager在frameworks目錄下,但前者作為一個服務,在單獨進程里為后者提供服務,后者則為應用進程提供接口服務,再通過binder進程通信訪問前者的服務,其關系如下,
?
?
?
?
3.2.6??????????InCallService
?
InCallService是一個抽象類,繼承于service,它由四大部分組成,Handler、InCallServiceBinder、VideoCall以及自身的一些方法,其中InCallServiceBinder是aidl接口的服務端實現,對應于前面提到的InCallController,它主要是給當前服務發送消息,Handler接收并處理這些消息,如前面提到,Handler會創建一個Telecom的Phone實例,然后使用Phone的接口處理應用請求,所以實際上,客戶端的請求實際上是Phone來完成的,至于Phone是如何實現功能的,請參見Phone的分析,這里的幾個關鍵類的相互關系如下,
?
?
InCallService的主要功能是給應用提供管理Phone call的途徑,它的子類InCallServiceImpl完成真正服務實例的創建,當存在呼叫連接時,它bind到Telecomm,并接受呼叫狀態的更新。
?
服務實例的綁定過程是在InCallController里面完成的,
?????private void bind() {…
????????????Intent serviceIntent = new Intent(InCallService.SERVICE_INTERFACE);
????????????for (ResolveInfo entry : packageManager.queryIntentServices(serviceIntent, 0)) {
????????????????????InCallServiceConnection inCallServiceConnection = new InCallServiceConnection();
????????????????????ComponentName componentName = new ComponentName(serviceInfo.packageName,
????????????????????????????serviceInfo.name);
????????????????????????Intent intent = new Intent(InCallService.SERVICE_INTERFACE);
????????????????????????intent.setComponent(componentName);
?
????????????????????????if (mContext.bindServiceAsUser(intent, inCallServiceConnection,
????????????????????????????????Context.BIND_AUTO_CREATE, UserHandle.CURRENT)) {
????????????????????????????mServiceConnections.put(componentName, inCallServiceConnection);
????????????????????????}
…}
這個bind()是在onCallAdded()里被調用的,onCallAdded被調用的地方有兩個:
CallsManager.java (packages\services\telecomm\src\com\android\server\telecom):????????????listener.onCallAdded(call);
Phone.java (frameworks\base\telecomm\java\android\telecom):????????????listener.onCallAdded(this, call);
?
他們都是通過listener的方式被調用的,通過分析兩個類的listener,發現Phone的監聽器主要在應用文件中注冊,
CallList.java (packages\apps\incallui\src\com\android\incallui):????????mPhone.addListener(mPhoneListener);
InCallPresenter.java (packages\apps\incallui\src\com\android\incallui):????????mPhone.addListener(mPhoneListener);
?
CallsManager的監聽器在其構造函數中注冊,并且監聽器類型為CallsManagerListener,
????private final Set<CallsManagerListener> mListeners = Collections.newSetFromMap(????????????new ConcurrentHashMap<CallsManagerListener, Boolean>(16, 0.9f, 1));
?
?????CallsManager(Context context, MissedCallNotifier missedCallNotifier,
?????????????PhoneAccountRegistrar phoneAccountRegistrar) {…
????????mCallLogManager = new CallLogManager(context);
????????mInCallController = new InCallController(context);
?
????????mListeners.add(statusBarNotifier);
????????mListeners.add(mCallLogManager);
????????mListeners.add(mPhoneStateBroadcaster);
????????mListeners.add(mInCallController);
????????mListeners.add(mRinger);
…}
所以是CallsManager. addCall調用了InCallController的onCallAdded。addCall則會被來電、去電、會議電話等接口方法調用,如startOutgoingCall。
?
所以當有通話連接要產生時,會啟動InCallService服務,其大致過程如下:
?
?
?
?
?
?
?
?
?
?
總結
以上是生活随笔為你收集整理的Android5.0 Telephony框架初步分析--telecomm的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 敏感词过滤及反垃圾文本的相关知识(欢迎收
- 下一篇: BEA助中国一汽构建核心ERP系统
