1. 程式人生 > >Android6.0來電流程

Android6.0來電流程

先放出6.0的MT時序圖大家有個直觀感受,下面程式碼一步步進行分析

這裡寫圖片描述

第一部分:RIL–>GSMPhone Call狀態變化 -> 發出來電通知(frameworks\opt\telephony)

1. framwork/opt/telephony/…/RIL.java

作用:RIL-Java在本質上就是一個RIL代理,起到一個轉發的作用,是Android Java概念空間中的電話系統的起點。 
RIL接收到RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED訊息

private void processUnsolicited (Parcel p) {
...
switch(response) {
...
case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED: if (RILJ_LOGD) unsljLog(response); 2、然後經由mCallStateRegistrants.notifyRegistrants發出通知 mCallStateRegistrants.notifyRegistrants(new AsyncResult(null, null, null));
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

BaseCommands.Java registerForCallStateChanged() mCallStateRegistrants.add(r);

 @Override
    public void registerForCallStateChanged(Handler h, int what, Object obj) {
        Registrant r = new Registrant (h, what, obj);
//新增到觀察者列表 
        mCallStateRegistrants.add(r);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

重點1:這其實是觀察者模式的一種實現形式 
1.RefistrantList 通知者 2.Registrant 觀察者,這是一個一對多的關係,在有事件更新時,凡是在名單上登記過的物件,都會收到通知。 
RegistrantList通知者支援對通知者的增加(add/addUnique)刪除(remove),並且能夠發出通知(notifyRegitrants);而Registrant作為觀察者,響應通知者發出的notifyRegistrant通知。 
整體上這個訊息註冊機制分為兩部分,訊息註冊和訊息通知。當呼叫regist方法時將Message存放進去,當其呼叫notify方法時將所有Message取出併發送到MessageQueue中等待處理。

3. framwork/opt/telephony/…GSMCallTracker.java

作用:GSMCallTracker在本質上是一個Handler。GSMCallTracker是Android的通話管理層。GSMCallTracker建立了ConnectionList來管理現行的通話連線,並向上層提供電話呼叫介面。 
查詢察者被呼叫的地方, 兩處被響應處理處理,其中一處:GSMCallTracker handleMessage

...//registerForCallStateChanged呼叫
 mCi.registerForCallStateChanged(this, EVENT_CALL_STATE_CHANGE, null);
...
 @Override
    public void
//響應處理
    handleMessage (Message msg) {
...
 case EVENT_CALL_STATE_CHANGE: //MT第一次
//呼叫父類CallTracker查詢Call List方法
     pollCallsWhenSafe();
     break;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

4、pollCallsWhenSafe()方法在CallTracker.java中實現

protected void pollCallsWhenSafe() {

        mNeedsPoll = true;

        if (checkNoOperationsPending()) {
            mLastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT);
    5//RIL.java中的getCurrentCalls方法  
            mCi.getCurrentCalls(mLastRelevantPoll);
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

回到RIL.java getCurrentCalls 將RIL_REQUEST_GET_CURRENT_CALLS 訊息封裝成RILRequest 
型別併發送。

@Override
    public void getCurrentCalls (Message result) {
        RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_CURRENT_CALLS, result);
        send(rr);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

RIL.java 有三處接收處理RIL_REQUEST_GET_CURRENT_CALLS訊息,真正的邏輯處理在processSolicited方法

private RILRequest processSolicited (Parcel p) {
...
case RIL_REQUEST_GET_CURRENT_CALLS: ret =  responseCallList(p); break;
...
if (rr.mResult != null) {
                    AsyncResult.forMessage(rr.mResult, ret, null);
                    rr.mResult.sendToTarget();//發出handler訊息通知
                }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

6、回到framworks/opt/telephony/…/telephony/gsm/GSMCallTracker.java

rr.mResult.sendToTarget()發出handler訊息通知後,會在GSMCallTracker中的handleMessage方法中響應。並且它的訊息型別是“EVENT_POLL_CALLS_RESULT”

@Override
    public void handleMessage (Message msg) {
        ...
        case EVENT_POLL_CALLS_RESULT:
                ar = (AsyncResult)msg.obj;
                if (msg == mLastRelevantPoll) {
                    mNeedsPoll = false;
                    mLastRelevantPoll = null;
         7、        handlePollCalls((AsyncResult)msg.obj);
                }
            break;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

8、handlePollCalls方法根據RIL發出的Call List物件判斷Call的狀態,併發出不同的通知,

1) 新來電的通知是: phone.notifyNewRingingConnection; 
另外兩個是 
2) 通話斷開通知 onDisconnected; 
3) Call狀態變化通知 phone.notifiyPreciseCallStateChanged. 
(當狀態改變之後便會通過GsmPhone的notifyPreciseCallStateChanged()方法發起響應) 
來電的時候發出的是phone.notifyNewRingConnection通知,進入到notifyNewRingConnection方法

handlePollCalls(){
...
if (newRinging != null) {
            mPhone.notifyNewRingingConnection(newRinging);
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

9、framworks/opt/telephony/…/telephony/gsm/GSMPhone.java

 public void notifyNewRingingConnection(Connection c) {
        super.notifyNewRingingConnectionP(c);
    }
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

呼叫父類 PhoneBase.java(為com.android.internal.telephony.phone介面實現。) 
notifyNewRingingConnectionP()發出來電通知 mNewRingingConnectionRegistrants.notifyRegistrants(ar);

/**
     * Notify registrants of a new ringing Connection.
     * Subclasses of Phone probably want to replace this with a
     * version scoped to their packages
     */
    public void notifyNewRingingConnectionP(Connection cn) {
        if (!mIsVoiceCapable)
            return;
        AsyncResult ar = new AsyncResult(null, cn, null);
        mNewRingingConnectionRegistrants.notifyRegistrants(ar);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

重點2: RegistrantList.java \frameworks\base\core\java\android\os 
notifyRegistrants方法實現

    public /*synchronized*/ void notifyRegistrants(AsyncResult ar){
        internalNotifyRegistrants(ar.result, ar.exception);
    }
    private synchronized void internalNotifyRegistrants (Object result, Throwable exception){
       for (int i = 0, s = registrants.size(); i < s ; i++) {
            Registrant  r = (Registrant) registrants.get(i);
            r.internalNotifyRegistrant(result, exception);
       }
    }
    /*package*/ void internalNotifyRegistrant (Object result, Throwable exception)
    {
        Handler h = getHandler();

        if (h == null) {
            clear();
        } else {
            Message msg = Message.obtain();

            msg.what = what;

            msg.obj = new AsyncResult(userObj, result, exception);

            h.sendMessage(msg);
        }
    }   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

註冊為觀察者的方法為:

// Inherited documentation suffices.
    @Override
    public void registerForNewRingingConnection(
            Handler h, int what, Object obj) {
        checkCorrectThread(h);

        mNewRingingConnectionRegistrants.addUnique(h, what, obj);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

通過log發現PstnIncomingCallNotifier.java呼叫registerForNewRingingConnection()

01-05 07:10:05.517962  1596  1596 D Telephony: PstnIncomingCallNotifier: handleNewRingingConnection
  • 1
  • 1
  • 1

第二部分:PstnIncomingCallNotifier–>Call 接收Framework層到通知–>準備建立連線

10、packages/services/Telephony/…/PstnIncomingCallNotifier.java(packages\services\telephony)

作用:監聽來之相關電話物件的來電事件和通知Telecom在每次發生的時候,這一例項的存在為了每個電話的通話服務

registerForNotifications方法呼叫registerForNewRingingConnection

    private void registerForNotifications() {
        Phone newPhone = mPhoneProxy.getActivePhone();
        if (newPhone != mPhoneBase) {
            unregisterForNotifications();

            if (newPhone != null) {
                Log.i(this, "Registering: %s", newPhone);
                mPhoneBase = newPhone;
                //呼叫registerForNewRingingConnection方法
                mPhoneBase.registerForNewRingingConnection(
                        mHandler, EVENT_NEW_RINGING_CONNECTION, null);
                mPhoneBase.registerForCallWaiting(
                        mHandler, EVENT_CDMA_CALL_WAITING, null);
                mPhoneBase.registerForUnknownConnection(mHandler, EVENT_UNKNOWN_CONNECTION,
                        null);
            }
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

11、handle 處理EVENT_NEW_RINGING_CONNECTION訊息

private final Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
        ...
            case EVENT_NEW_RINGING_CONNECTION:
                    handleNewRingingConnection((AsyncResult) msg.obj);
                    break;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

12、從之前的log看: 由handleNewRingingConnection方法,處理新的來電連線。

    private void handleNewRingingConnection(AsyncResult asyncResult) {
        Log.d(this, "handleNewRingingConnection");
        Connection connection = (Connection) asyncResult.result;
        if (connection != null) {
            Call call = connection.getCall();

            //在傳送intent到Telecom之前最後一次驗證ringing 狀態
            if (call != null && call.getState().isRinging()) {
                sendIncomingCallIntent(connection);
            }
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

13、sendIncomingCallIntent方法

傳送incoming 
call intent到telecom,傳送的Connection 型別,裡面包括isIncoming getState isRinging等

    /**
     * Sends the incoming call intent to telecom.
     */
    private void sendIncomingCallIntent(Connection connection) {
        Bundle extras = null;
        if (connection.getNumberPresentation() == TelecomManager.PRESENTATION_ALLOWED &&
                !TextUtils.isEmpty(connection.getAddress())) {
            extras = new Bundle();
            Uri uri = Uri.fromParts(PhoneAccount.SCHEME_TEL, connection.getAddress(), null);
            extras.putParcelable(TelephonyManager.EXTRA_INCOMING_NUMBER, uri);
        }
        TelecomManager.from(mPhoneProxy.getContext()).addNewIncomingCall(
                TelecomAccountRegistry.makePstnPhoneAccountHandle(mPhoneProxy), extras);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

14、addNewIncomingCall()定義在: framworks/base/telecomm/java/android/telecom/TelecomManager.java

作用:TelecomManager的功能則主要是對TelecomService提供的遠端介面的封裝,然後提供給應用使用。 
來電時觸發 addNewIncomingCall方法


    @SystemApi
    public void addNewIncomingCall(PhoneAccountHandle phoneAccount, Bundle extras) {
        try {
            if (isServiceConnected()) {
                getTelecomService().addNewIncomingCall(
                        phoneAccount, extras == null ? new Bundle() : extras);
            }
        } catch (RemoteException e) {
            Log.e(TAG, "RemoteException adding a new incoming call: " + phoneAccount, e);
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 相關推薦

    Android6.0來電流程

    先放出6.0的MT時序圖大家有個直觀感受,下面程式碼一步步進行分析 第一部分:RIL–>GSMPhone Call狀態變化 -> 發出來電通知(frameworks\opt\telephony) 1. framwork/opt/telephony/…/RIL.ja

    Android6.0來電號碼電話薄名稱匹配

    本文將介紹系統接收到來電之後,如何在電話薄中進行匹配聯絡人的流程。分析將從另外一篇文章(基於Android6.0的RIL框架層模組分析)中提到的與本文內容相關的程式碼開始。 //packages/service/***/Call.java public void handleCr

    Android6.0 Telephony流程分析——PhoneApp啟動主要類關係分析

    本文程式碼以MTK平臺Android 6.0為分析物件,與Google原生AOSP有些許差異,請讀者知悉。 PhoneApp(包名com.android.phone)主要程式碼位於 packages/

    高通 NXP NFC(PN547PN548) 移植流程 android6.0

    一、驅動部分 首先向NXP 的 fae要android 6.0 bring up的程式碼,如:NFC_NCIHALx_AR0F.4.3.0_M_NoSE 結構目錄如下: 1. 新增驅動檔案 高通平臺需使用pn544節點,所以將驅動中的裝置節點名字修改為pn544即可; 2. 修改平臺配置 在init.qco

    android Telephony學習 --- 第七篇 android7.0 來電(MT)流程

    我們先看下7.0來電大體流程: ##Framework modem接收到來電通知訊息後,以AT指令的方式上報RIL層,RIL層通過sokcet將訊息傳送給RILJ, 上報事件ID: RIL_UNSOL

    Android6.0 原始碼修改之遮蔽系統簡訊功能和來電功能

    一、遮蔽系統簡訊功能 1、遮蔽所有簡訊 android 4.2 簡訊傳送流程分析可參考這篇 戳這 原始碼位置 vendor\mediatek\proprietary\packages\apps\Mms\src\com\android\mms\trans

    [RK3288][Android6.0] RTC驅動的上層呼叫流程

    Platform: Rockchip OS: Android 6.0 Kernel: 3.10.92 說明: RTC驅動在註冊的時候提供了兩個字元裝置給使用者空間供操作。 1. /dev/alarm, android特有裝置,為了提高平臺無關性而加

    [RK3288][Android6.0] 系統除錯串列埠驅動流程小結

    Platform: ROCKCHIP OS: Android 6.0 Kernel: 3.10.92 rk3288提供了fiq debugger功能, 因此rk將debug uart和普通uart區分開來, debug uart的初始化整合到了fiq debugger程式碼中完成,不過uart的初始化 方法還

    android6.0系統Healthd分析及低電量自動關機流程

      系統平臺:android6.0概述Healthd是android4.4之後提出來的一種中介模型,該模型向下監聽來自底層的電池事件,向上傳遞電池資料資訊給Framework層的BatteryService用以計算電池電量相關狀態資訊,BatteryServcie通過傳遞來的資料來計算電池電量顯示

    Android6.0亮屏流程之Keyguard Window繪製

    亮滅屏問題一直是Android模組最常見的問題之一。        由於問題出現問題的地方涉及到公司程式碼,我這裡僅僅只作原生程式碼模組的分析        其實在看過另外一篇關於android亮屏

    Android6.0 Reset恢復出廠設定流程分析

    點選Settings應用中的恢復出廠設定按鈕後流程分析:先使用grep命令搜尋"恢復出廠設定"字串,找到相應的佈局檔案: packages/apps/Settings/res/xml/privacy_settings.xml <PreferenceScree

    [Android6.0][RK3399] Type-C 驅動流程分析

    基本概念 USB 控制器 OHCI(Open Host Controller Interface) 是支援USB1.1的標準,但它不僅僅是針對USB,還支援其他的一些介面,比如它還支援Apple的火線(Firewire,IEEE 1394

    [Android6.0][RK3399] 雙屏異顯程式碼實現流程分析(一)

    Platform: RK3399 OS: Android 6.0 Version: v2016.08 本文分為兩部分。 《[RK3399] 雙屏異顯程式碼實現流程分析(一)》為分析 RK video 部分標準的程式碼(base on 2017.

    [RK3288][Android6.0] 系統按鍵驅動流程分析

    Rockchip的按鍵驅動位於 kernel/drivers/input/keyboard/rk_keys.c 預設支援的keys在dts中定義: 其中power key作為普通gpio,具有喚醒功能。而其他按鍵比如,volume up/down 可以通

    [RK3288][Android6.0] DDR Frequency控制流程小結

        freq-table = <        /*status        freq(KHz)*/        SYS_STATUS_NORMAL    400000        SYS_STATUS_SUSPEND    200000        SYS_STATUS_VIDEO_108

    android6.0 開機啟動流程

    這篇部落格講下android開機啟動流程,init那部分之前在分析init程序的時候,講過了,我們就不看了。當然我們結合log看。 整個開機的時間,我們一SurfaceFlinger來算,先從如下log開始,下面這句log,是在SurfaceFlinger的建構函式的第一句

    [RK3288][Android6.0] Audio的音量設定流程小結

    Platform: Rockchip OS: Android 6.0 Kernel: 3.10.92 說明一:  AudioManager提供了兩個調節音量介面 adjustSuggestedSt

    [RK3288][Android6.0] 網路服務Netd初始化流程小結

    Platform: Rockchip OS: Android 6.0 Kernel: 3.10.92 Netd: Network Daemon. 負責網路配置,操作,管理,查詢等功能. 封裝底層各種型別網路,如PPP,SOFTAP等,給framework提供統一介面. 說

    Android6.0系統啟動流程分析三:SystemServer程序

    在上一篇部落格 Android6.0系統啟動流程分析二:zygote程序一文中,我們隊Zygote程序的有了一定的瞭解。我們知道Zygote程序會啟動SystemServer程序,但我們並沒有在上篇文章中分析SystemServer程序的相關內容。這篇部落格,我

    Android6.0 Telephony Frameworks之資料業務建立流程

    資料業務(資料網路,即SIM卡上網)的建立需滿足兩個條件:1.選擇並激活合適的APN;2.PS域已處於Attached狀態。預設狀態下,手機開機後就會發起PS附著的信令給網路。而所有資料網路的請求(開啟關閉資料開關、切換資料卡、修改APN等)都必須經過DcTacker.ja