Android7.0 Phone应用源码分析 phone来电流程分析
Posted 蓝斯老师
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android7.0 Phone应用源码分析 phone来电流程分析相关的知识,希望对你有一定的参考价值。
接上篇博文:Android7.0 Phone应用源码分析(一) phone拨号流程分析
今天我们再来分析下Android7.0 的phone的来电流程
1.1TelephonyFramework
当有来电通知时,首先接收到消息的是Modem层,然后Medoem再上传给RIL层,RIL进程通过sokcet将消息发送给RILJ(framework层的RIL),同样进入RILJ的processResponse方法,根据上一章节去电流程的分析得知,来电属于UnSolicited消息,事件ID是
RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED,看看RILJ里的处理
com.android.internal.telephony.RIL
processUnsolicited (Parcel p, int type) { ……………………………… switch(response) { case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED: ret = responseVoid(p);
break; ……………………………… } ……………………………… switch(response) { case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED: if (RILJ_LOGD) unsljLog(response); mCallStateRegistrants .notifyRegistrants(new AsyncResult(null, null, null)); break; ……………………………… } ……………………………… }
mCallStateRegistrants是RegistrantList实例,这里用到了观察者模式,mCallStateRegistrants将call状态的变化通知给了所有感兴趣的注册者,BaseCommands提供了相关注册接口
com.android.internal.telephony. registerForCallStateChanged @Override public void registerForCallStateChanged(Handler h, int what, Object obj) { Registrant r = new Registrant (h, what, obj); mCallStateRegistrants.add(r); } }
最后找到GsmCdmaCallTracker在创建的时候注册了该事件
com.android.internal.telephony. GsmCdmaCallTracker public GsmCdmaCallTracker (GsmCdmaPhone phone) { this.mPhone = phone; mCi = phone.mCi; mCi.registerForCallStateChanged(this, EVENT_CALL_STATE_CHANGE, null); mCi.registerForOn(this, EVENT_RADIO_AVAILABLE, null); mCi.registerForNotAvailable(this, EVENT_RADIO_NOT_AVAILABLE, null); ...... ...... }
收到EVENT_CALL_STATE_CHANGE消息后进入pollCallsWhenSafe方法
protected void pollCallsWhenSafe() { mNeedsPoll = true; if (checkNoOperationsPending()) { mLastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT); mCi.getCurrentCalls(mLastRelevantPoll); }} }
这里的处理流程跟之前拨号类似,同样是通过RILJ获取当前call状态,收到回应后进入handlePollCalls方法
protected synchronized void handlePollCalls(AsyncResult ar) { ……………………………… if (newRinging != null) { // 新来电通知 mPhone.notifyNewRingingConnection(newRinging); } ……………………………… updatePhoneState(); // 更新phone状态 ……………………………… if (hasNonHangupStateChanged || newRinging != null || hasAnyCallDisconnected) { mPhone.notifyPreciseCallStateChanged(); // 发出call状态变化通知 } }
新来电进入phone的notifyNewRingingConnection的方法
com.android.internal.telephony.Phone public void notifyNewRingingConnectionP(Connection cn) { if (!mIsVoiceCapable) return; AsyncResult ar = new AsyncResult(null, cn, null); mNewRingingConnectionRegistrants.notifyRegistrants(ar);} }
又是一个观察者模式,最后找到是注册了该事件的监听对象PstnIncomingCallNotifier
1.2TelephonyService
com.android.services.telephony. PstnIncomingCallNotifier private void registerForNotifications() { if (mPhone != null) { Log.i(this, "Registering: %s", mPhone); mPhone.registerForNewRingingConnection(mHandler, EVENT_NEW_RINGING_CONNECTION, null); mPhone.registerForCallWaiting(mHandler, EVENT_CDMA_CALL_WAITING, null); mPhone.registerForUnknownConnection(mHandler, EVENT_UNKNOWN_CONNECTION, null); } }
Handler处理消息进入handleNewRingingConnection方法
private void handleNewRingingConnection(AsyncResult asyncResult) { Log.d(this, "handleNewRingingConnection"); Connection connection = (Connection) asyncResult.result; if (connection != null) { Call call = connection.getCall(); // Final verification of the ringing state before sending the intent to Telecom. if (call != null && call.getState().isRinging()) { sendIncomingCallIntent(connection); } } }
获取到call对象以后,最后进入sendIncomingCallIntent
private void sendIncomingCallIntent(Connection connection) { ……………………………… PhoneAccountHandle handle = findCorrectPhoneAccountHandle(); if (handle == null) { try { connection.hangup(); } catch (CallStateException e) { // connection already disconnected. Do nothing } } else { TelecomManager.from(mPhone.getContext()).addNewIncomingCall(handle, extras); } }
通过aidl接口调用telecomservice的的addNewIncomingCall方法
1.3 TelecomService
TelecomServiceImpl的成员变量mBinderImpl是具体实现类
com.android.server.telecom.TelecomServiceImpl private final ITelecomService.Stub mBinderImpl = new ITelecomService.Stub(){ 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); } ……………………………… }
这里调用到的是CallIntentProcessor 的processIncomingCallIntent方法
com.android.server.telecom. CallIntentProcessor static void processIncomingCallIntent(CallsManager callsManager, Intent intent) { ……………………………… Log.d(CallIntentProcessor.class, "Processing incoming call from connection service [%s]", phoneAccountHandle.getComponentName()); callsManager.processIncomingCallIntent(phoneAccountHandle, clientExtras); }
进入callsmanager的processIncomingCallIntent方法
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); }
走到这一步,跟之前分析的拨号流程一样,创建了一个call对象,然后调用
startCreateConnection创建连接,根据之前拨号的流程分析最后会进入 ConnectionService的createConnection方法
1.4 TelecommFramework
再把实现代码贴一遍:
private void createConnection(final PhoneAccountHandle callManagerAccount, final String callId,
final ConnectionRequest request, boolean isIncoming, boolean isUnknown) { ……………………………… Connection connection = isUnknown ? onCreateUnknownConnection(callManagerAccount, request) : isIncoming ? onCreateIncomingConnection(callManagerAccount, request) : onCreateOutgoingConnection(callManagerAccount, request);
……………………………… mAdapter.handleCreateConnectionComplete( callId, request, new ParcelableConnection( request.getAccountHandle(), connection.getState(), connection.getConnectionCapabilities(), connection.getConnectionProperties(), connection.getAddress(), connection.getAddressPresentation(), connection.getCallerDisplayName(), connection.getCallerDisplayNamePresentation(), connection.getVideoProvider() == null ? null : connection.getVideoProvider().getInterface(), connection.getVideoState(), connection.isRingbackRequested(), connection.getAudioModeIsVoip(), connection.getConnectTimeMillis(), connection.getStatusHints(), connection.getDisconnectCause(), createIdList(connection.getConferenceables()), connection.getExtras(), connection.getUserData()));//MOTO Calling Code - IKPIM-1774 (ftr 33860) if (isUnknown) { triggerConferenceRecalculate(); } }
这里由于是来电,所以调用onCreateIncomingConnection方法,该方法同样返回null,所以具体是由其子类实现的,也就是TelephonyConnectionService
public Connection onCreateIncomingConnection( PhoneAccountHandle connectionManagerPhoneAccount, ConnectionRequest request) { Connection connection = createConnectionFor(phone, originalConnection, false /* isOutgoing */, request.getAccountHandle(), request.getTelecomCallId(), request.getAddress()); if (connection == null) { return Connection.createCanceledConnection(); } else { return connection; } }
最后根据GMS或是CDMA返回对应Connection对象,最后进入ConnectionServiceAdapter处理
android.telecom. ConnectionServiceAdapter void handleCreateConnectionComplete( String id, ConnectionRequest request, ParcelableConnection connection) { for (IConnectionServiceAdapter adapter : mAdapters) { try { adapter.handleCreateConnectionComplete(id, request, connection); } catch (RemoteException e) { } } }
这里的adapter实际上就是ConnectionServiceWrapper的内部类Adapter,需要注意的是之前拨号的时候创建完connection并呼出之后,后续也会走到这个流程里
public void handleCreateConnectionComplete(String callId, ConnectionRequest request, ParcelableConnection connection) { Log.startSession("CSW.hCCC"); long token = Binder.clearCallingIdentity(); try { synchronized (mLock) { logIncoming("handleCreateConnectionComplete %s", callId); ConnectionServiceWrapper.this handleCreateConnectionComplete(callId, request, connection); } } finally { Binder.restoreCallingIdentity(token); Log.endSession(); } }
最后进入handleCreateConnectionComplete方法
private void handleCreateConnectionComplete( String callId, ConnectionRequest request, ParcelableConnection connection) { // TODO: Note we are not using parameter "request", which is a side effect of our tacit // assumption that we have at most one outgoing connection attempt per ConnectionService. // This may not continue to be the case. if (connection.getState() == Connection.STATE_DISCONNECTED) { // A connection that begins in the DISCONNECTED state is an indication of // failure to connect; we handle all failures uniformly removeCall(callId, connection.getDisconnectCause()); } else { // Successful connection if (mPendingResponses.containsKey(callId)) { mPendingResponses.remove(callId).handleCreateConnectionSuccess(mCallIdMapper, connection); } } }
这里的mPendingResponses是map容器
private final Map<String, CreateConnectionResponse> mPendingResponses = new HashMap<>();
ConnectionServiceWrapper在调用createConnection的时候会往该容器里添加对象,也就是CreateConnectionProcessor对象
public void handleCreateConnectionSuccess( CallIdMapper idMapper, ParcelableConnection connection) { if (mCallResponse == null) { // Nobody is listening for this connection attempt any longer; ask the responsible // ConnectionService to tear down any resources associated with the call mService.abort(mCall); } else { // Success -- share the good news and remember that we are no longer interested // in hearing about any more attempts mCallResponse.handleCreateConnectionSuccess(idMapper, connection); mCallResponse = null; // If there\'s a timeout running then don\'t clear it. The timeout can be triggered // after the call has successfully been created but before it has become active. } }
这个mCallResponse是CreateConnectionProcessor创建的时候引入的,也就是call对象
com.android.server.telecom.Call public void handleCreateConnectionSuccess( CallIdMapper idMapper, ParcelableConnection connection) { switch (mCallDirection) { case CALL_DIRECTION_INCOMING: for (Listener l : mListeners) { l.onSuccessfulIncomingCall(this); } break; case CALL_DIRECTION_OUTGOING: for (Listener l : mListeners) { l.onSuccessfulOutgoingCall(this, getStateFromConnectionState(connection.getState())); } break; case CALL_DIRECTION_UNKNOWN: for (Listener l : mListeners) { l.onSuccessfulUnknownCall(this, getStateFromConnectionState(connection .getState())); } break; } }
这里根据是来电还是去电类型,执行相应回调,监听者会收到通知,来电事件则触发onSuccessfulIncomingCall的回调
1.5 TelecommService
前面提到CallsManager在执行processIncomingCallIntent方法时候会创建call,之后就会给call添加监听,所以最后会回调到CallsManager类
public void onSuccessfulIncomingCall(Call incomingCall) { Log.d(this, "onSuccessfulIncomingCall"); List<IncomingCallFilter.CallFilter> filters = new ArrayList<>(); filters.add(new DirectToVoicemailCallFilter(mCallerInfoLookupHelper)); filters.add(newAsyncBlockCheckFilter
(mContext, new BlockCheckerAdapter())); filters.add(new CallScreeningServiceFilter(mContext, this, mPhoneAccountRegistrar, mDefaultDialerManagerAdapter, new ParcelableCallUtils.Converter(), mLock)); newIncomingCallFilter
(mContext, this, incomingCall, mLock, mTimeoutsAdapter, filters).performFiltering(); }
这里用到了一个迭代器模式,一个来电操作触发这三个对象的处理:
DirectToVoicemailCallFilter,AsyncBlockCheckFilter,CallScreeningServiceFilter
生成一个IncomingCallFilter对象,调用performFiltering方法
com.android.server.telecom.callfiltering. IncomingCallFilter public void performFiltering() { Log.event(mCall, Log.Events.FILTERING_INITIATED); for (CallFilter filter : mFilters) { filter.startFilterLookup(mCall, this); } 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())); }
他们依次执行startFilterLookup异步查询方法,通过回调方法并将结果CallFilteringResult传回onCallFilteringComplete将CallFilteringResult对象传递回来
public class CallFilteringResult { public boolean shouldAllowCall; // 是否允许通话 public boolean shouldReject; // 是否拒接 public boolean shouldAddToCallLog; // 是否添加至通话记 public boolean shouldShowNotification; // 是否显示通知栏消息 ……………………………… ……………………………… } public void onCallFilteringComplete(Call call, CallFilteringResult result) { synchronized (mTelecomLock) { // synchronizing to prevent race on mResult mNumPendingFilters--; mResult = result.combine(mResult); if (mNumPendingFilters == 0) { mHandler.post(new Runnable("ICF.oCFC") { @Override public void loggedRun() { // synchronized to enter into Telecom. synchronized (mTelecomLock) { if (mIsPending) { mListener.onCallFilteringComplete(mCall, mResult); mIsPending = false; } } } }.prepare()); } } }
先看看DirectToVoicemailCallFilter对象,它处理的是voicemail相关信息,
实际上是由CallerInfoLookupHelper完成查询的,内部调用CallerInfoAsyncQueryFactory的startQuery方法,而CallerInfoAsyncQueryFactory是个接口类,在CallsManager创建的时候由外部传参进来,最后找到是TelecomService的initializeTelecomSystem里创建的
com.android.server.telecom.components. TelecomService static void initializeTelecomSystem(Context context) { new CallerInfoAsyncQueryFactory() { @Override public CallerInfoAsyncQuery startQuery( int token, Context context, String number, CallerInfoAsyncQuery.OnQueryCompleteListener listener, Object cookie) { Log.i(TelecomSystem.getInstance(), "CallerInfoAsyncQuery.startQuery number=%s cookie=%s", Log.pii(number), cookie); return CallerInfoAsyncQuery.startQuery( token, context, number, listener, cookie); } }
进入CallerInfoAsyncQuery的startQuery方法
com.android.internal.telephony.CallerInfoAsyncQuery public static CallerInfoAsyncQuery startQuery(int token, Context context, String number, OnQueryCompleteListener listener, Object cookie, int subId) { final Uri contactRef = PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI.buildUpon() .appendPath(number) .appendQueryParameter(PhoneLookup.QUERY_PARAMETER_SIP_ADDRESS, String.valueOf(PhoneNumberUtils.isUriNumber(number))) .build(); }
查询的uri是PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI
返回cursor结果集后转化成CallerInfo,其中shouldSendToVoicemail变量查询的
是PhoneLookup.SEND_TO_VOICEMAIL字段
public static CallerInfo getCallerInfo(Context context, Uri contactRef, Cursor cursor) { ...... ...... ...... ...... columnIndex = cursor.getColumnIndex(PhoneLookup.SEND_TO_VOICEMAIL); info.shouldSendToVoicemail = (columnIndex != -1) && ((cursor.getInt(columnIndex)) == 1); info.contactExists = true; ...... ...... }
最后回到DirectToVoicemailCallFilter的查询回调,shouldSendToVoicemail为true时表示允许通话,否则是拒接
if (info.shouldSendToVoicemail) { result = new CallFilteringResult( false, // shouldAllowCall true, // shouldReject true, // shouldAddToCallLog true // shouldShowNotification ); } else { result = new CallFilteringResult( true, // shouldAllowCall false, // shouldReject true, // shouldAddToCallLog true // shouldShowNotification ); } }
再看看AsyncBlockCheckFilter,它处理的是黑名单事件
判断一个电话号码是否在黑名单里调用到了BlockChecker的isBlocked方法
com.android.internal.telephony. BlockChecker public static boolean isBlocked(Context context, String phoneNumber) { boolean isBlocked = false; long startTimeNano = System.nanoTime(); try { if (BlockedNumberContract.SystemContract.shouldSystemBlockNumber( context, phoneNumber)) { Rlog.d(TAG, phoneNumber + " is blocked."); isBlocked = true; } } catch (Exception e) { Rlog.e(TAG, "Exception checking for blocked number: " + e); } int durationMillis = (int) ((System.nanoTime() - startTimeNano) / 1000000); if (durationMillis > 500 || VDBG) { Rlog.d(TAG, "Blocked number lookup took: " + durationMillis + " ms."); } return isBlocked; }
BlockedNumberContract.SystemContract是framework里的一个黑名单协议类
public static final String AUTHORITY = "com.android.blockednumber"; public static final String METHOD_SHOULD_SYSTEM_BLOCK_NUMBER = "should_system_block_number"; public static boolean shouldSystemBlockNumber(Context context, String phoneNumber) { final Bundle res = context.getContentResolver().call( AUTHORITY_URI, METHOD_SHOULD_SYSTEM_BLOCK_NUMBER, phoneNumber, null); return res != null && res.getBoolean(RES_NUMBER_IS_BLOCKED, false); }
黑名单是BlockedNumberProvider数据库, 调用call方法
com.android.providers.blockednumber. BlockedNumberProvider @Override public Bundle call(@NonNull String method, @Nullable String arg, @Nullable Bundle extras) { final Bundle res = new Bundle(); switch (method) { case SystemContract.METHOD_SHOULD_SYSTEM_BLOCK_NUMBER: enforceSystemReadPermissionAndPrimaryUser(); res.putBoolean( BlockedNumberContract.RES_NUMBER_IS_BLOCKED, shouldSystemBlockNumber(arg)); break; ............ ............ } } private boolean shouldSystemBlockNumber(String phoneNumber) { if (getBlockSuppressionStatus().isSuppressed) { return false; } if (isEmergencyNumber(phoneNumber)) { return false; } return isBlocked(phoneNumber); }
最后调用isBlocked方法查询blocked表中是否存在该number
查询得到结果后返回
CallFilteringResult result; if (isBlocked) { result = new CallFilteringResult( false, // shouldAllowCall true, //shouldReject false, //shouldAddToCallLog false // shouldShowNotification ); } else { result = new CallFilteringResult( true, // shouldAllowCall false, // shouldReject true, // shouldAddToCallLog true // shouldShowNotification ); }
如果号码在黑名单里则拦截
最后是CallScreeningServiceFilter不知道是处理什么,内部绑定一个抽象服务
CallScreeningService但是却找不到哪个子类继承了它,这里先忽略它
回到前面IncomingCallFilter的onCallFilteringCompletev方法,结果集会做个逻辑运算
mResult = result.combine(mResult);看看它的实现
com.android.server.telecom.callfilteringCallFilteringResult public CallFilteringResult combine(CallFilteringResult other) { if (other == null) { return this; } return new CallFilteringResult( shouldAllowCall && other.shouldAllowCall, shouldReject || other.shouldReject, shouldAddToCallLog && other.shouldAddToCallLog, shouldShowNotification && other.shouldShowNotification); }
只有三个过滤结果都是允许通话才允许通话,添加至通话记录以及是否显示到通知栏同理
当然这里的查询操作也有超时限制,时间是5秒,超过5秒后忽略还未查询到的过滤器则被忽略mTimeoutsAdapter.getCallScreeningTimeoutMillis(mContext.getContentResolver()));
最后过滤结果被回调到CallsManager的onCallFilteringComplete
public void onCallFilteringComplete(Call incomingCall, CallFilteringResult result) { ……………………………… if (incomingCall.getState() != CallState.DISCONNECTED && incomingCall.getState() != CallState.DISCONNECTING) { setCallState(incomingCall, CallState.RINGING, result.shouldAllowCall? "successful incoming call" : "blocking call"
); } else { Log.i(this, "onCallFilteringCompleted: call already disconnected."); } if (result.shouldAllowCall) { if (hasMaximumRingingCalls()) { rejectCallAndLog(incomingCall); } else if (hasMaximumDialingCalls()) { rejectCallAndLog(incomingCall); } else { addCall(incomingCall); } } else { if (result.shouldReject) { incomingCall.reject(false, null); } if (result.shouldAddToCallLog) { mCallLogManager.logCall(incomingCall, Calls.MISSED_TYPE, result.shouldShowNotification); } else以上是关于Android7.0 Phone应用源码分析 phone来电流程分析的主要内容,如果未能解决你的问题,请参考以下文章Android7.0 Phone应用源码分析 phone拨号流程分析
android6.0 Phone源码分析之Phone适配过程