android Telephony學習 --- 第七篇 android7.0 來電(MT)流程
阿新 • • 發佈:2018-12-12
我們先看下7.0來電大體流程:
##Framework
modem接收到來電通知訊息後,以AT指令的方式上報RIL層,RIL層通過sokcet將訊息傳送給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實現了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);
}
更新狀態,傳送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 建立call之後,CreateConnection建立連結,之後的流程和撥出流程類似:
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 主要執行關於攔截來電的,是否是黑名單等資訊,此篇不關注此處流程:
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 實現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);
}
}