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

我們先看下7.0來電大體流程:


7.0來電流程.png

Framework

modem接收到來電通知消息后乎芳,以AT指令的方式上報RIL層敛滋,RIL層通過sokcet將消息發(fā)送給RILJ烦味, 上報事件ID: RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED:

  • frameworks/opt/telephony – RIL
    private void processUnsolicited (Parcel p, int type) {
           case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED:
                if (RILJ_LOGD) unsljLog(response);
                mCallStateRegistrants
                    .notifyRegistrants(new AsyncResult(null, null, null));
            break;
  • frameworks/opt/telephony – BaseCommands
    mCallStateRegistrants在BaseCommands中添加的觀察者方法苍凛,在GsmCdmaCallTracker中注冊了registerForCallStateChanged方法:
    @Override
    public void registerForCallStateChanged(Handler h, int what, Object obj) {
        Registrant r = new Registrant (h, what, obj);
        mCallStateRegistrants.add(r);
    }
  • frameworks/opt/telephony – GsmCdmaCallTracker
   public GsmCdmaCallTracker (GsmCdmaPhone phone) {
        mCi = phone.mCi;
        mCi.registerForCallStateChanged(this, EVENT_CALL_STATE_CHANGE, null);

接著找到EVENT_CALL_STATE_CHANGE消息:

            case EVENT_CALL_STATE_CHANGE:
                pollCallsWhenSafe();
            break;
  • frameworks/opt/telephony – CallTracker
    找到GsmCdmaCallTracker父類的方法pollCallsWhenSafe:
    protected void pollCallsWhenSafe() {
        mNeedsPoll = true;
        if (checkNoOperationsPending()) {
            mLastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT);
            mCi.getCurrentCalls(mLastRelevantPoll);
        }
    }
  • frameworks/opt/telephony – RIL
    找到CommandsInterface mCi徒扶,而其RIL implements CommandsInterface實現(xiàn)了getCurrentCalls方法粮彤,,攜帶消息
    EVENT_POLL_CALLS_RESULT:
    @Override
    public void getCurrentCalls (Message result) {
        RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_CURRENT_CALLS, result);
        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
        send(rr);
    }
  • frameworks/opt/telephony – GsmCdmaCallTracker
    和之前流程類似姜骡,接著進入handlePollCalls方法:
 case EVENT_POLL_CALLS_RESULT:
                Rlog.d(LOG_TAG, "Event EVENT_POLL_CALLS_RESULT Received");
                if (msg == mLastRelevantPoll) {
                    if (DBG_POLL) log(
                            "handle EVENT_POLL_CALL_RESULT: set needsPoll=F");
                    mNeedsPoll = false;
                    mLastRelevantPoll = null;
                    handlePollCalls((AsyncResult)msg.obj);
                }

更新狀態(tài)驾诈,發(fā)送call state change通知等:

     if (newRinging != null) {
            mPhone.notifyNewRingingConnection(newRinging);
         }
        updatePhoneState();
        if (hasNonHangupStateChanged || newRinging != null || hasAnyCallDisconnected) {
            mPhone.notifyPreciseCallStateChanged();
        }
  • frameworks/opt/telephony – Phone
    notifyNewRingingConnectionP方法:
    /**
     * 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);
    }

Telephony

  • packages/service/Telephony – PstnIncomingCallNotifier
    找到注冊registerForNewRingingConnection處,
    消息EVENT_NEW_RINGING_CONNECTION調用handleNewRingingConnection:
         mPhone.registerForNewRingingConnection(mHandler, EVENT_NEW_RINGING_CONNECTION, null);

         case EVENT_NEW_RINGING_CONNECTION:
               handleNewRingingConnection((AsyncResult) msg.obj);
               break;

Framework

  • frameworks/base/telecomm – TelecomManager
    addNewIncomingCall方法
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);
        }
    }

Telecom

  • packages/services/Telecom – TelecomServiceImpl
    找到對應的ITelecomServic aidl接收的地方,查看addNewIncomingCall方法:
  private final ITelecomService.Stub mBinderImpl = new ITelecomService.Stub() {
   @Override
        public void addNewIncomingCall(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
              Intent intent = new Intent(TelecomManager.ACTION_INCOMING_CALL);
                            intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
                                    phoneAccountHandle);
              intent.putExtra(CallIntentProcessor.KEY_IS_INCOMING_CALL, true);
              if (extras != null) {
                       extras.setDefusable(true);
                                intent.putExtra(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS, extras);
                            }
             mCallIntentProcessorAdapter.processIncomingCallIntent(
                                    mCallsManager, intent); 
  • packages/services/Telecom – CallIntentProcessor
    static void processIncomingCallIntent(CallsManager callsManager, Intent intent) {
        callsManager.processIncomingCallIntent(phoneAccountHandle, clientExtras);
    }
  • packages/services/Telecom – CallsManager
    創(chuàng)建call之后溶浴,CreateConnection創(chuàng)建鏈接乍迄,之后的流程和呼出流程類似:
   void processIncomingCallIntent(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
        Call call = new Call(
                getNextCallId(),
                mContext,
                this,
                mLock,
                mConnectionServiceRepository,
                mContactsAsyncHelper,
                mCallerInfoAsyncQueryFactory,
                handle,
                null /* gatewayInfo */,
                null /* connectionManagerPhoneAccount */,
                phoneAccountHandle,
                Call.CALL_DIRECTION_INCOMING /* callDirection */,
                false /* forceAttachToExistingConnection */,
                false /* isConference */
        );
        call.addListener(this);
        call.startCreateConnection(mPhoneAccountRegistrar);
    }
  • packages/services/Telecom – Call
void startCreateConnection(PhoneAccountRegistrar phoneAccountRegistrar) {
    mCreateConnectionProcessor = new CreateConnectionProcessor(this, mRepository, this,
            phoneAccountRegistrar, mContext);
    mCreateConnectionProcessor.process();
}
  • packages/services/Telecom – CreateConnectionProcessor
@VisibleForTesting
public void process() {
    Log.v(this, "process");
    clearTimeout();
    mAttemptRecords = new ArrayList<>();
    if (mCall.getTargetPhoneAccount() != null) {
        mAttemptRecords.add(new CallAttemptRecord(
                mCall.getTargetPhoneAccount(), mCall.getTargetPhoneAccount()));
    }
    adjustAttemptsForConnectionManager();
    adjustAttemptsForEmergency();
    mAttemptRecordIterator = mAttemptRecords.iterator();
    attemptNextPhoneAccount();
}
  • packages/services/Telecom – ConnectionServiceWrapper
mServiceInterface.createConnection(

        call.getConnectionManagerPhoneAccount(),
        callId,
        new ConnectionRequest(
                call.getTargetPhoneAccount(),
                call.getHandle(),
                extras,
                call.getVideoState(),
                callId),
        call.shouldAttachToExistingConnection(),
        call.isUnknown());

Frameworks

  • frameworks/base/telecomm -- ConnectionService
    呼出時是調用onCreateOutgoingConnection,此篇是呼入士败,需要查看onCreateIncomingConnection
Connection connection = isUnknown ? onCreateUnknownConnection(callManagerAccount, request)
        : isIncoming ? onCreateIncomingConnection(callManagerAccount, request)
        : onCreateOutgoingConnection(callManagerAccount, request);

Telecom

  • packages/services/Telecom – Call
 public void handleCreateConnectionSuccess(
    switch (mCallDirection) {
        case CALL_DIRECTION_INCOMING:
            // Listeners (just CallsManager for now) will be responsible for checking whether
            // the call should be blocked.
            for (Listener l : mListeners) {
                l.onSuccessfulIncomingCall(this);
            }
            break;
  • packages/services/Telecom – CallsManager
@Override
public void onSuccessfulIncomingCall(Call incomingCall) {
    Log.d(this, "onSuccessfulIncomingCall");
    List<IncomingCallFilter.CallFilter> filters = new ArrayList<>();
    filters.add(new DirectToVoicemailCallFilter(mCallerInfoLookupHelper));
    filters.add(new AsyncBlockCheckFilter(mContext, new BlockCheckerAdapter()));
    filters.add(new CallScreeningServiceFilter(mContext, this, mPhoneAccountRegistrar,
            mDefaultDialerManagerAdapter,
            new ParcelableCallUtils.Converter(), mLock));
    new IncomingCallFilter(mContext, this, incomingCall, mLock,
            mTimeoutsAdapter, filters).performFiltering();
}
  • packages/services/Telecom – IncomingCallFilter
    主要執(zhí)行關于攔截來電的闯两,是否是黑名單等信息褥伴,此篇不關注此處流程:
public void performFiltering() {
    mHandler.postDelayed(new Runnable("ICF.pFTO") { // performFiltering time-out
        @Override
        public void loggedRun() {
            // synchronized to prevent a race on mResult and to enter into Telecom.
            synchronized (mTelecomLock) {
                if (mIsPending) {
                    Log.i(IncomingCallFilter.this, "Call filtering has timed out.");
                    Log.event(mCall, Log.Events.FILTERING_TIMED_OUT);
                    mListener.onCallFilteringComplete(mCall, mResult);
                    mIsPending = false;
                }
            }
        }
    }.prepare(), mTimeoutsAdapter.getCallScreeningTimeoutMillis(mContext.getContentResolver()));
}
  • packages/services/Telecom – CallsManager
   @Override
   public void onCallFilteringComplete(Call incomingCall, CallFilteringResult result) {
          addCall(incomingCall);
      }
    private void addCall(Call call) {
        for (CallsManagerListener listener : mListeners) {
            listener.onCallAdded(call);}
  • packages/services/Telecom – InCallController
    和呼入篇類似漾狼,附相關代碼:
@Override
public void onCallAdded(Call call) {
    if (!isBoundToServices()) {
        bindToServices(call);
    } else {
        addCall(call);
        inCallService.addCall(parcelableCall);
}

Frameworks

  • frameworks/base/telecomm – InCallService
    實現(xiàn)aidl方法addCall重慢,找到消息MSG_ADD_CALL:
private final class InCallServiceBinder extends IInCallService.Stub {
    @Override
    public void setInCallAdapter(IInCallAdapter inCallAdapter) {
        mHandler.obtainMessage(MSG_SET_IN_CALL_ADAPTER, inCallAdapter).sendToTarget();
    }
    @Override
    public void addCall(ParcelableCall call) {
        mHandler.obtainMessage(MSG_ADD_CALL, call).sendToTarget();
    }
    case MSG_ADD_CALL:
    mPhone.internalAddCall((ParcelableCall) msg.obj);
    break;
  • frameworks/base/telecomm -- Phone
final void internalAddCall(ParcelableCall parcelableCall) {
    Call call = new Call(this, parcelableCall.getId(), mInCallAdapter,
            parcelableCall.getState());
    mCallByTelecomCallId.put(parcelableCall.getId(), call);
    mCalls.add(call);
    checkCallTree(parcelableCall);
    call.internalUpdate(parcelableCall, mCallByTelecomCallId);
    fireCallAdded(call);
 }
private void fireCallAdded(Call call) {
    for (Listener listener : mListeners) {
        listener.onCallAdded(this, call);
    }
}
  • frameworks/base/telecomm – InCallService
@Override
public void onCallAdded(Phone phone, Call call) {
    InCallService.this.onCallAdded(call);
}

Dialer

  • packages/app/Dialer -- InCallServiceImpl
@Override
public void onCallAdded(Call call) {
   InCallPresenter.getInstance().onCallAdded(call);}

  • packages/app/Dialer -- InCallPresenter
public void onCallAdded(final android.telecom.Call call) {
    if (shouldAttemptBlocking(call)) {
        maybeBlockCall(call);
    } else {
        mCallList.onCallAdded(call);
    }
}
@Override
public void onIncomingCall(Call call) {
    InCallState newState = startOrFinishUi(InCallState.INCOMING);
    InCallState oldState = mInCallState;
    for (IncomingCallListener listener : mIncomingCallListeners) {
        listener.onIncomingCall(oldState, mInCallState, call);
    }
}
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市逊躁,隨后出現(xiàn)的幾起案子似踱,更是在濱河造成了極大的恐慌,老刑警劉巖稽煤,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件核芽,死亡現(xiàn)場離奇詭異,居然都是意外死亡酵熙,警方通過查閱死者的電腦和手機轧简,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來匾二,“玉大人哮独,你說我怎么就攤上這事〔烀辏” “怎么了皮璧?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長分飞。 經常有香客問我恶导,道長,這世上最難降的妖魔是什么浸须? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任惨寿,我火速辦了婚禮,結果婚禮上删窒,老公的妹妹穿的比我還像新娘裂垦。我一直安慰自己,他們只是感情好肌索,可當我...
    茶點故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布蕉拢。 她就那樣靜靜地躺著,像睡著了一般诚亚。 火紅的嫁衣襯著肌膚如雪晕换。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天站宗,我揣著相機與錄音闸准,去河邊找鬼。 笑死梢灭,一個胖子當著我的面吹牛夷家,可吹牛的內容都是我干的蒸其。 我是一名探鬼主播,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼库快,長吁一口氣:“原來是場噩夢啊……” “哼摸袁!你這毒婦竟也來了?” 一聲冷哼從身側響起义屏,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤靠汁,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后闽铐,有當地人在樹林里發(fā)現(xiàn)了一具尸體蝶怔,經...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年阳啥,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片财喳。...
    茶點故事閱讀 38,094評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡察迟,死狀恐怖,靈堂內的尸體忽然破棺而出耳高,到底是詐尸還是另有隱情扎瓶,我是刑警寧澤,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布泌枪,位于F島的核電站概荷,受9級特大地震影響,放射性物質發(fā)生泄漏碌燕。R本人自食惡果不足惜误证,卻給世界環(huán)境...
    茶點故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望修壕。 院中可真熱鬧愈捅,春花似錦、人聲如沸慈鸠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽青团。三九已至譬巫,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間督笆,已是汗流浹背芦昔。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留娃肿,地道東北人烟零。 一個月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓瘪松,卻偏偏與公主長得像,于是被迫代替她去往敵國和親锨阿。 傳聞我的和親對象是個殘疾皇子宵睦,可洞房花燭夜當晚...
    茶點故事閱讀 42,828評論 2 345

推薦閱讀更多精彩內容