Version:1.0 StartHTML:0000000174 EndHTML:0000527746 StartFragment:0000129196 EndFragment:0000527706 SourceURL:file:///Y:\Desktop\Dialer\Android去电流程%203.18.docx

Android去电流程

目录

目录.... 2

1. 简介.... 3

1.1.      概述... 3

1.2.      适用范围... 3

1.3.      详细流程图... 3

2.Dialer层流程.... 4

2.1.      模块简介... 4

2.2.      流程分析... 4

2.3.      关键代码及log. 4

3.Telecom层流程.... 5

3.1.      模块简介... 5

3.2.      流程分析... 5

3.3.      关键代码及log. 5

4.Frameworks telecom层流程.... 6

4.1.      模块简介... 6

4.2.      流程分析... 6

4.3.      关键代码及log. 6

5.Telephony层流程.... 7

5.1.      模块简介... 7

5.2.      流程分析... 7

5.3.      关键代码及log. 7

6.Frameworks Telephony层流程.... 8

6.1.      模块简介... 8

6.2.      流程分析... 8

6.3.      关键代码及log. 8

  1. 简介

    1. 概述

此文档详细的介绍了android中的去电流程,一直从上层(dialer)到底层(RIL)层的详细流程,可以让相关的同事在解决去电问题的时候快速的定位问题点,方便了bug的fix。

  1. 适用范围

此问题使用了android P平台,高通和MTK均适用。

  1. 详细流程图
  1. 层流程

    1. 模块简介

      1. 概述

手机最基本的功能包括两个大的方面,一个是打电话功能,一个是短信功能,我们这里的Dialer模块指的就是打电话功能的一部分,他是手机与用户交互的桥梁,提供图形界面来给用户操作,使用户能够通过一系列的操作拨打电话等等。

从源码的包的命名,可以将Dialer分为四个大的部分,包含:contact、incallui、dialer、voicemial。Contact主要是联系人相关的逻辑,与Contact模块有着很大的联系;incallui主要是通话过程中的incall界面的东西,在通话过程中,设计到很多的与底层交与的逻辑,需要调用底层的接口来获取电话状态并显示在incall界面上,需要调用底层接口来对call进行操作;dialer主要是点击app图标进入之后的界面的显示、界面相关操作的逻辑以及一部分dialer的设置;voicemial是voicemail相关的代码,调用的是底层的接口。

  1. 流程分析
  1. 关键代码及log

这一个部分代码逻辑较为简单,且代码中没有打印关键log,所以这一部分就不贴关键代码以及关键log,只要关注上一个部分的流程就可以。

  1. 层流程

    1. 模块简介

      1. 概述

这里的Telecom层指的是位于packages/services/Telecomm的模块,是android 5.0之后从phone进程中提出来的位于incallui(也就是dialer进程)和phone进程(telephony)之间的模块,运行于系统进程之中。基本上所有的incallui界面上的显示相关的信息都是从这个模块中调用接口获取而来的,而这个模块实质上是没有和底层打交道的,他上面链接dialer,下面链接的是framework/base/telecom,所以可以把他看做是一个中间层的接口,涉及到底层的东西是没有放在这里处理的。

实际上,在这个模块中,我认为最最重要的需要我们来关注的类,就是TelecomServiceImpl.java,基本上所有的call相关的重要方法,都是放在这个类中来实现的。

  1. 流程分析

    1. 流程图
    1. 分析
  1. 检查一些权限相关的东西,然后创建一个UserCallIntentProcessor,调用它的processIntent方法。
  1. 从intent中取出action,判断action是否等于ACTION_CALL||ACTION_CALL_PRIVILEGED||ACTION_CALL_EMERGENCY。如果相等,调用processOutgoingCallIntent方法
  1. 对号码的uri做了以下处理,判断传入的正在拨号的dialer是不是默认dialer,存入intent中(CallIntentProcessor.KEY_IS_PRIVILEGED_DIALER)。然后调用sendIntentToDestination方法
  1. 在这个方法中会判断isLocalInvocation,这个参数是从TelecomServiceImpl中的placeCall方法传过来的,默认是true。如果是false,就会发送广播到PrimaryCallReceiver,然后调用CallIntentProcessor的processIntent方法。如果是true,则会直接调用CallIntentProcessor的processIntent方法,这样就省去了中间的广播接受时间,性能更加优异。
  1. 在processIntent方法中,从intent中判断KEY_IS_UNKNOWN_CALL是否是true,如果是,则调用processUnknownCallIntent方法,如果不是,调用processOutgoingCallIntent方法。
  1. 对号码的uri进行处理,判断是sip号码还是普通号码,添加上scheme,将call相关的信息封装到Bundle中,然后调用callsmanager的startOutgoingCall方法。
  1. 在startOutgoingCall方法中,创建了一个call对象,并调用call.setTargetPhoneAccount方法设置了call的phone账户,并判断是否需要选择账户,如果需要,设置call的State为CallState.SELECT_PHONE_ACCOUNT,如果不需要,就将call的状态设置为CallState.CONNECTING,并在这个方法中判断传入的Bundle中是否含有TelecomManager.EXTRA_START_CALL_WITH_RTT,如果是true,则表示用户拨出的是rtt call,会调用call.setRequestedToStartWithRtt()方法去启动rtt。然后调用addCall方法,在这个方法中,会遍历call状态变化的观察者并逐个回调通知,这里的观察者比较多,在callsManager创建的时候注册监听的,call状态的改变会通知到这些观察者(里面包含了一个重要的观察者:incallcontroller,它内部封装了与incallui服务的相关操作,实际上就是一个远程服务代理类,当callsmanager添加一路call时, 回调InCallController的onCallAdded方法,最后调用inCallService的addCall方法告诉incallui当前添加了一路通话,incallui收到后会拉起界面)。初始化完毕call,返回给processOutgoingCallIntent方法,接着调用sendNewOutgoingCallIntent。
  1. 创建一个NewOutgoingCallIntentBroadcaster对象,调用他的processIntent方法。这个方法是有返回值的,如果返回值不等于DisconnectCause.NOT_DISCONNECTED,那么就会在这里挂断电话并弹出提示框提示。
  1. 在processIntent方法中,会判断号码是不是voicemail,如果是,会调用placeOutgoingCallImmediately方法去拨打电话。如果不是,会先调用rewriteCallIntentAction方法去修改action,因为传入的action有三种:

普通call Intent.ACTION_CALL

系统call Intent.ACTION_CALL_PRIVILEGED

紧急呼叫call Intent.ACTION_CALL_EMERGENCY

普通call任何应用都可以发起,第三方应用拨号都是使用该intent;系统call只有系统应用才能使用;紧急呼叫call 同样只有系统应用才能使用,并且可以在无卡状态下呼出。对于一个Intent.ACTION_CALL_PRIVILEGED的拨号请求,会根据当前号码是否为紧急号码来转化该intent,如果是紧急号码则转化为Intent.ACTION_CALL_EMERGENCY如果不是紧急号码则转化为Intent.ACTION_CALL,所以实际上处理call只有两种情况Intent.ACTION_CALL和Intent.ACTION_CALL_EMERGENCY。

对于Intent.ACTION_CALL的处理:

如果当前是紧急号码,会校验调用者是否为系统默认拨号盘,如果是则置变量callImmediately为true,后续直接呼出该电话。如果不是则拉起系统默认拨号盘,当前方法调用返回DisconnectCause.OUTGOING_CANCELED

对于Intent.ACTION_CALL_EMERGENCY的处理:

直接设置变量callImmediately为true,直接呼出该电话。

所以如果callImmediately参数为true,会直接调用placeOutgoingCallImmediately方法来拨打电话,不会去发送广播。而如果这个参数为false,会调用broadcastIntent方法来拨打电话。

  1. 在broadcastIntent方法中,调用sendOrderedBroadcastAsUser方法发送了广播。
  1. NewOutgoingCallIntentBroadcast的onReceive方法接收到这个广播,最后还是调用placeOutgoingCallImmediately方法来拨打电话。
  1. 在placeOutgoingCallImmediately方法中,将call的mIsNewOutgoingCallIntentBroadcastDone参数设置为了true,表示NewOutgoingCallIntentBroadcast完毕,接着调用callsmanager的placeOutgoingCall方法。
  1. 在callsmanager的placeOutgoingCall方法中,会检查是否需要打开扬声器,如果需要会打开扬声器。然后调用call的startCreateConnection方法去创建Connection。
  2. startCreateConnection方法中创建了一个CreateConnectionProcessor对象,然后调用它的process方法。
  1. 向mAttemptRecords中加入当前电话的CallAttemptRecord对象,实质上就是两个PhoneAccountHandle对象。然后调用attemptNextPhoneAccount方法。
  1. 在attemptNextPhoneAccount方法中,首先会判断mAttemptRecords列表中的PhoneAccountHandle是否具有BIND_TELECOM_CONNECTION_SERVICE权限,判断是否能够绑定链接,然后调用ConnectionServiceRepository的getService()方法得到mService,而mService是一个ConnectionServiceWrapper类的实例对象,我们可以把ConnectionServiceWrapper看做是一个代理类,因为其父类ServiceBinder是一个抽象类,且绑定了一个远程服务,然后调用ConnectionServiceWrapper.java的createConnection方法。
  1. 在createConnection方法中,会创建一个BindCallback对象,实现它的onSuccess和onFailure方法,创建完毕之后,会调用mBinder.bind(callback, call)方法去绑定,如果绑定成功,就会回调BindCallback的onSuccess方法 。
    1. 关键代码及log

      1. 关键代码
  1. TelecomServiceImpl.java

public void placeCall(Uri handle, Bundle extras, String callingPackage) {

.......................

//创建一个UserCallIntentProcessor对象,调用它的processIntent方法

 mUserCallIntentProcessorFactory.create(mContext, userHandle)

             .processIntent(

               intent, callingPackage, isSelfManaged ||

                 (hasCallAppOp && hasCallPermission),

                 true /* isLocalInvocation */);

......................

}

  1. UserCallIntentProcessor.java

public void processIntent(Intent intent, String callingPackageName,

boolean canCallNonEmergency, boolean isLocalInvocation) {

............................

//从intent中取出action,如果等于以下三种,则调用processOutgoingCallIntent方法继续//处理

String action = intent.getAction();

if (Intent.ACTION_CALL.equals(action) ||

Intent.ACTION_CALL_PRIVILEGED.equals(action) ||

Intent.ACTION_CALL_EMERGENCY.equals(action)) {

            processOutgoingCallIntent(intent, callingPackageName, canCallNonEmergency, isLocalInvocation);

}

}

  1. UserCallIntentProcessor.java

private void processOutgoingCallIntent(Intent intent, String callingPackageName,

boolean canCallNonEmergency, boolean isLocalInvocation) {

..................................

//调用sendIntentToDestination方法来准备发送广播

        sendIntentToDestination(intent, isLocalInvocation);

..................................

}

  1. UserCallIntentProcessor.java

private boolean sendIntentToDestination(Intent intent, boolean isLocalInvocation) {

.......................

//设置广播的接收者为PrimaryCallReceiver

intent.setClass(mContext, PrimaryCallReceiver.class);

//这里会判断isLocalInvocation这个值,如果是true,会直接调用CallIntentProcessor的//processIntent方法来拨号,不需要来发送广播,省去了一些拨号的时间。实质上,如果是//false, PrimaryCallReceiver接收到广播之后还是调用的CallIntentProcessor的//processIntent方法

//这个值是TelecomServiceImpl.java中的placeCall方法调用UserCallIntentProcessor的//processIntent方法时传入的,一直传到了这里

if (isLocalInvocation) {

// getCallIntentProcessor方法返回一个CallIntentProcessor对象             TelecomSystem.getInstance().getCallIntentProcessor().processIntent(intent);

} else {

            mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM);

}

return true;

}

  1. CallIntentProcessor.java

public void processIntent(Intent intent) {

.......................

//判断isUnknownCall,如果是调用processUnknownCallIntent方法.否则调用//processOutgoingCallIntent方法.

final boolean isUnknownCall = intent.getBooleanExtra(KEY_IS_UNKNOWN_CALL, false);

if (isUnknownCall) {

processUnknownCallIntent(mCallsManager, intent);

} else {

processOutgoingCallIntent(mContext, mCallsManager, intent);

}

}

  1. CallIntentProcessor.java

static void processOutgoingCallIntent(

Context context,

CallsManager callsManager,

Intent intent) {

..................................

//调用callsManager的startOutgoingCall方法,创建一个call对象

Call call = callsManager

                .startOutgoingCall(handle, phoneAccountHandle, clientExtras, initiatingUser,

intent);

...................................

}

public Call startOutgoingCall(Uri handle, PhoneAccountHandle phoneAccountHandle, Bundle extras,

UserHandle initiatingUser, Intent originalIntent) {

//检查是否有可以复用的call对象,如果有,后面就不需要创建

Call call = reuseOutgoingCall(handle);

//通过传入的phoneAccountHandle来获取PhoneAccount对象,这里phoneAccountHandle为空,所以PhoneAccount对象拿到也是空

PhoneAccount account =

mPhoneAccountRegistrar.getPhoneAccount(phoneAccountHandle, initiatingUser);

//isSelfManaged参数为false

boolean isSelfManaged = account != null && account.isSelfManaged();

//创建call对象

if (call == null) {

call = new Call(getNextCallId(), mContext,

this,

mLock,

mConnectionServiceRepository,

mContactsAsyncHelper,

mCallerInfoAsyncQueryFactory,

mPhoneNumberUtilsAdapter,

handle,

null /* gatewayInfo */,

null /* connectionManagerPhoneAccount */,

null /* phoneAccountHandle */,

Call.CALL_DIRECTION_OUTGOING /* callDirection */,

false /* forceAttachToExistingConnection */,

false, /* isConference */

mClockProxy);

if ((extras != null) &&

extras.getBoolean(TelephonyProperties.EXTRA_DIAL_CONFERENCE_URI, false)) {

//Reset PostDialDigits with empty string for ConfURI call.

call.setPostDialDigits("");

}

call.initAnalytics();

...................

//获取能够拨打电话的PhoneAccountHandle,如果只有一个,选用这个,如果不是,则继续往下走

List<PhoneAccountHandle> potentialPhoneAccounts = findOutgoingCallPhoneAccount(

phoneAccountHandle, handle, VideoProfile.isVideo(videoState),

initiatingUser, scheme);

if (potentialPhoneAccounts.size() == 1) {

phoneAccountHandle = potentialPhoneAccounts.get(0);

} else {

phoneAccountHandle = null;

}

call.setTargetPhoneAccount(phoneAccountHandle);

//判断是不是MMICODE

boolean isPotentialInCallMMICode = isPotentialInCallMMICode(handle) && !isSelfManaged;

....................................

//之前获取的能够拨打电话的PhoneAccountHandle的数量如果大于1,就需要让用户选择账户

boolean needsAccountSelection =

phoneAccountHandle == null && potentialPhoneAccounts.size() > 1

&& !call.isEmergencyCall() && !isSelfManaged;

if (needsAccountSelection) {

call.setState(CallState.SELECT_PHONE_ACCOUNT, "needs account selection");

extras = new Bundle(extras);

extras.putParcelableList(android.telecom.Call.AVAILABLE_PHONE_ACCOUNTS,

potentialPhoneAccounts);

}

.............................

//设置call的状态为CONNECTING

call.setState(

CallState.CONNECTING,

phoneAccountHandle == null ? "no-handle" : phoneAccountHandle.toString());

//判断rtt功能是否打开,如果打开,调用setRequestedToStartWithRtt去启动rtt call

if (isRttSettingOn() || (extras != null

&& extras.getBoolean(TelecomManager.EXTRA_START_CALL_WITH_RTT, false))) {

Log.d(this, "Outgoing call requesting RTT, rtt setting is %b", isRttSettingOn());

if (accountToUse != null

&& accountToUse.hasCapabilities(PhoneAccount.CAPABILITY_RTT)) {

call.createRttStreams();

}

call.setRequestedToStartWithRtt();

}

}

..................................

if ((isPotentialMMICode(handle) || isPotentialInCallMMICode) && !needsAccountSelection) {

//如果是MMICODE,CallsManager实现了Call的Listener接口,并添加了监听

call.addListener(this);

} else if (!mCalls.contains(call) && mPendingMOEmerCall == null) {.

//重要方法addcall,后面会单独说

addCall(call);

}

return call;

}

public void addCall(Call call) {

//首先先给call添加listener,call状态的改变会回调callsmanager实现的Listener的接口.

 call.addListener(this);

//将创建的call对象添加到mCalls中,方便后面的管理

mCalls.add(call);

Bundle extras = call.getIntentExtras();

extras.putLong(TelecomManager.EXTRA_CALL_TELECOM_ROUTING_END_TIME_MILLIS,

SystemClock.elapsedRealtime());

.................

//通知每一个listener,调用他们的onCallAdded方法.实质上,很多的方法都是call对象变化,回调他的Listener对象callsmanager的对应方法,然后callsmanager再回调他的Listener对象的方法

 for (CallsManagerListener listener : mListeners) {

if (LogUtils.SYSTRACE_DEBUG) {

Trace.beginSection(listener.getClass().toString() + " addCall");

}

listener.onCallAdded(call);

if (LogUtils.SYSTRACE_DEBUG) {

Trace.endSection();

}

}

Trace.endSection();

}

//在callsmanager的构造方法中可以看到,很多都在这里注册了监听器,call对象的改变都会通知到这些listener,重点可以关注加粗的监听器,当回调它的onCallAdded方法时,就会去启动InCallActivity(在InCallControlleronCallAdded方法中回去调用bindToServices方法来绑定服务,绑定成功之后会调用InCallServiceImpl.java的onBind方法,在这个方法中就会调用InCallPresenter.getInstance().maybeStartRevealAnimation(intent)来启动activity)

mListeners.add(mInCallWakeLockController);

mListeners.add(statusBarNotifier);

mListeners.add(mCallLogManager);

mListeners.add(mPhoneStateBroadcaster);

        mListeners.add(mInCallController);

mListeners.add(mCallAudioManager);

mListeners.add(mCallRecordingTonePlayer);

mListeners.add(missedCallNotifier);

mListeners.add(mHeadsetMediaButton);

mListeners.add(mProximitySensorManager);

  1. CallIntentProcessor.java

static void processOutgoingCallIntent(

Context context,

CallsManager callsManager,

Intent intent) {

..................................

//对call对象做判空处理,不为空时调用sendNewOutgoingCallIntent方法继续拨号流程

if (call != null) {

sendNewOutgoingCallIntent(context, call, callsManager, intent);

}

}

  1. CallIntentProcessor.java

static void sendNewOutgoingCallIntent(Context context, Call call, CallsManager callsManager,

Intent intent) {

//创建一个NewOutgoingCallIntentBroadcaster对象,调用他的processIntent方法

NewOutgoingCallIntentBroadcaster broadcaster = new NewOutgoingCallIntentBroadcaster(

context, callsManager, call, intent, callsManager.getPhoneNumberUtilsAdapter(),

isPrivilegedDialer);

final int result = broadcaster.processIntent();

............................

}

  1. NewOutgoingCallIntentBroadcaster.java

public int processIntent() {

..........................

//判断是不是voicemial

boolean isVoicemailNumber = PhoneAccount.SCHEME_VOICEMAIL.equals(handle.getScheme());

if (isVoicemailNumber) {

.....................

}

...........................

//获取电话号码

number = mPhoneNumberUtilsAdapter.getNumberFromIntent(intent, mContext);

.........................

//如果action是ACTION_CALL_PRIVILEGED,则将它转化为ACTION_CALL_EMERGENCY或者是ACTION_CALL,所以实际上处理的action只有两种,就是ACTION_CALL_EMERGENCY和ACTION_CALL

rewriteCallIntentAction(intent, isPotentialEmergencyNumber);

action = intent.getAction();

if (Intent.ACTION_CALL.equals(action)) {

if (isPotentialEmergencyNumber) {

if (!mIsDefaultOrSystemPhoneApp) {

Log.w(this, "Cannot call potential emergency number %s with CALL Intent %s "

+ "unless caller is system or default dialer.", number, intent);

launchSystemDialer(intent.getData());

return DisconnectCause.OUTGOING_CANCELED;

} else {

//如果号码是紧急号码,callImmediately设置为true

callImmediately = true;

}

}

} else if (Intent.ACTION_CALL_EMERGENCY.equals(action)) {

if (!isPotentialEmergencyNumber) {

Log.w(this, "Cannot call non-potential-emergency number %s with EMERGENCY_CALL "

+ "Intent %s.", number, intent);

return DisconnectCause.OUTGOING_CANCELED;

}

//如果action是ACTION_CALL_EMERGENCY,callImmediately设置为true

callImmediately = true;

}

.........................................

//直接调用placeOutgoingCallImmediately方法进行拨号流程,这里直接调用的话就会跳过发送广播的流程,在时间上能够至少节省100毫秒

if (callImmediately) {

..........................

   placeOutgoingCallImmediately(mCall, callingAddress, null,

                    speakerphoneOn, videoState);

}

if (sendNewOutgoingCallBroadcast) {

..............................

//调用broadcastIntent方法来发送广播,注意第三个参数,如果上面调用了placeOutgoingCallImmediately这个方法,callImmediately就为true,传入的参数也就是false

   broadcastIntent(intent, number, !callImmediately, targetUser);

}

return DisconnectCause.NOT_DISCONNECTED;

}

  1. NewOutgoingCallIntentBroadcaster.java

private void broadcastIntent(

Intent originalCallIntent,

String number,

boolean receiverRequired,

UserHandle targetUser) {

....................

//发送广播,注意,这里的receiverRequired如果为true,就不会去指定接收者.

mContext.sendOrderedBroadcastAsUser(

broadcastIntent,

targetUser,

android.Manifest.permission.PROCESS_OUTGOING_CALLS,

AppOpsManager.OP_PROCESS_OUTGOING_CALLS,

receiverRequired ? new NewOutgoingCallBroadcastIntentReceiver() : null,

null,  // scheduler

Activity.RESULT_OK,  // initialCode

number,  // initialData: initial value for the result data (number to be modified)

null);  // initialExtras

}

  1. NewOutgoingCallIntentBroadcaster.java

public void onReceive(Context context, Intent intent) {

..............................

//这个方法中主要是对号码进行一些处理,然后调用placeOutgoingCallImmediately继续拨号流程

 placeOutgoingCallImmediately(mCall, resultHandleUri, gatewayInfo,

                            mIntent.getBooleanExtra(

                                    TelecomManager.EXTRA_START_CALL_WITH_SPEAKERPHONE, false),

                            mIntent.getIntExtra(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,

                                    VideoProfile.STATE_AUDIO_ONLY));

..............................

}

  1. NewOutgoingCallIntentBroadcaster.java

private void placeOutgoingCallImmediately(Call call, Uri handle, GatewayInfo gatewayInfo,

boolean speakerphoneOn, int videoState) {

//将call对象的mIsNewOutgoingCallIntentBroadcastDone设置为true,然后调用callsmanager的placeOutgoingCall方法继续拨号流程

mCall.setNewOutgoingCallIntentBroadcastIsDone();

mCallsManager.placeOutgoingCall(call, handle, gatewayInfo, speakerphoneOn, videoState);

}

  1. CallsManager.java

public void placeOutgoingCall(Call call, Uri handle, GatewayInfo gatewayInfo,

boolean speakerphoneOn, int videoState) {

.......................................

//判断扬声器是否需要打开,如果需要,则打开扬声器.默认使用的是听筒

final boolean useSpeakerWhenDocked = mContext.getResources().getBoolean(

R.bool.use_speaker_when_docked);

final boolean useSpeakerForDock = isSpeakerphoneEnabledForDock();

final boolean useSpeakerForVideoCall = isSpeakerphoneAutoEnabledForVideoCalls(videoState);

call.setStartWithSpeakerphoneOn(speakerphoneOn || useSpeakerForVideoCall

                || (useSpeakerWhenDocked && useSpeakerForDock));

...........................................

//判断phoneAccount是否能够使用,判断当前的outgoingcaLL\DialingCall\LiveCall\HoldingCall是否已经到达上限

final boolean isOutgoingCallPermitted = isOutgoingCallPermitted(call,

call.getTargetPhoneAccount());

final String callHandleScheme =

call.getHandle() == null ? null : call.getHandle().getScheme();

//再次确认call的TargetPhoneAccount成员变量是否为空

if (call.getTargetPhoneAccount() != null || call.isEmergencyCall()) {

............................

//调用call对象的startCreateConnection方法来创建Connection

call.startCreateConnection(mPhoneAccountRegistrar);

............................

}

  1. Call.java

void startCreateConnection(PhoneAccountRegistrar phoneAccountRegistrar) {

//创建一个CreateConnectionProcessor对象,这个对象用来创建outgoingcall的链接和incomingcall的连接

mCreateConnectionProcessor = new CreateConnectionProcessor(this, mRepository, this,

phoneAccountRegistrar, mContext);

//实例化完毕调用他的process方法

mCreateConnectionProcessor.process();

}

  1. CreateConnectionProcessor.java

public void process() {

//实例化mAttemptRecords对象

mAttemptRecords = new ArrayList<>();

if (mCall.getTargetPhoneAccount() != null) {

//将这一通call的PhoneAccountHandle放入mAttemptRecords中

mAttemptRecords.add(new CallAttemptRecord(

mCall.getTargetPhoneAccount(), mCall.getTargetPhoneAccount()));

}

//调用attemptNextPhoneAccount方法继续流程

mAttemptRecordIterator = mAttemptRecords.iterator();

attemptNextPhoneAccount();

}

  1. CreateConnectionProcessor.java

private void attemptNextPhoneAccount() {

.....................

//判断PhoneAccountHandle是否具有绑定服务的权限,如果没有,则使用下一个PhoneAccountHandle,这里都是递归方法,

//如果没有权限就会一直调用attemptNextPhoneAccount,直到mAttemptRecordIterator遍历完毕

if (!mPhoneAccountRegistrar.phoneAccountRequiresBindPermission(

attempt.connectionManagerPhoneAccount)) {

Log.w(this,

"Connection mgr does not have BIND_TELECOM_CONNECTION_SERVICE for "

+ "attempt: %s", attempt);

attemptNextPhoneAccount();

return;

}

.......................................

if (mCallResponse != null && attempt != null) {

Log.i(this, "Trying attempt %s", attempt);

//取出能够具有权限的能够绑定服务的PhoneAccountHandle

PhoneAccountHandle phoneAccount = attempt.connectionManagerPhoneAccount;

//调用ConnectionServiceRepository对象的getService方法来获取service,就是一个ConnectionServiceWrapper对象

mService = mRepository.getService(phoneAccount.getComponentName(),

phoneAccount.getUserHandle());

//如果服务为空,继续递归

if (mService == null) {

Log.i(this, "Found no connection service for attempt %s", attempt);

attemptNextPhoneAccount();

} else {

//为call设置TargetPhoneAccount\ConnectionService等

mConnectionAttempt++;

mCall.setConnectionManagerPhoneAccount(attempt.connectionManagerPhoneAccount);

mCall.setTargetPhoneAccount(attempt.targetPhoneAccount);

mCall.setConnectionService(mService);

//设置建立连接的时间,如果很长时间未建立成功,就会超时

setTimeoutIfNeeded(mService, attempt);

..................................

mCall.getConnectionServiceFocusManager().requestFocus(

mCall,

new CallsManager.RequestCallback(new CallsManager.PendingAction() {

@Override

public void performAction() {

Log.d(this, "perform create connection");

//调用就是一个ConnectionServiceWrapper对象的createConnection方法来创建连接

                                    mService.createConnection(

                                            mCall,

                                            CreateConnectionProcessor.this);

}

}));

}

}

} else {

//建立失败将会通知挂断case,弹出dialog提示

DisconnectCause disconnectCause = mLastErrorDisconnectCause != null ?

mLastErrorDisconnectCause : new DisconnectCause(DisconnectCause.ERROR);

            notifyCallConnectionFailure(disconnectCause);

}

}

  1. ConnectionServiceWrapper.java

public void createConnection(final Call call, final CreateConnectionResponse response) {

//创建一个回调对象,实现他的onSuccess方法和onFailure方法,成功或失败的时候会回调这个方法

 BindCallback callback = new BindCallback() {

//绑定服务成功会回调这个方法

@Override

public void onSuccess() {

...........................

//开始创建连接,packages/services/Telecomm部分流程结束,接下来将会调用到/frameworks/base/telecomm/java/android/telecom/ConnectionService.java中的createConnection方法

                    mServiceInterface.createConnection(

                            call.getConnectionManagerPhoneAccount(),

                            callId,

                            connectionRequest,

                            call.shouldAttachToExistingConnection(),

                            call.isUnknown(),

                            Log.getExternalSession());

}

@Override

public void onFailure() {

Log.e(this, new Exception(), "Failure to call %s", getComponentName());

response.handleCreateConnectionFailure(new DisconnectCause(DisconnectCause.ERROR));

}

};

//绑定service,绑定成功之后会回调上面的onSuccess方法

mBinder.bind(callback, call);

}

  1. 关键log

   

03-14 11:04:50.131   919  2943 I Telecom : Call: setState 0 -> 1: TSI.pC@AR8

03-14 11:04:50.133   919  2943 I Telecom : Event: RecordEntry TC@1: SET_CONNECTING, ComponentInfo{com.android.phone/com.android.services.telephony.TelephonyConnectionService}, ***, UserHandle{0}: TSI.pC@AR8

03-14 11:04:50.156   919  2943 I Telecom : CallsManager: addCall([TC@1, CONNECTING, null, tel:*****, A, childs(0), has_parent(false), [Capabilities:], [Properties:]]): TSI.pC@AR8

03-14 11:04:50.158   919  2943 I Telecom : InCallController: onCallAdded: [TC@1, CONNECTING, null, tel:*****, A, childs(0), has_parent(false), [Capabilities:], [Properties:]]; not bound or connected.: TSI.pC@AR8

03-14 11:04:50.162   919  2943 I Telecom : EmergencyInCallServiceConnection: Attempting to bind to InCall [ComponentInfo{com.google.android.dialer/com.android.incallui.InCallServiceImpl} supportsExternal? true supportsSelfMg?false], with Intent { act=android.telecom.InCallService cmp=com.google.android.dialer/com.android.incallui.InCallServiceImpl (has extras) }: TSI.pC@AR8

03-14 11:04:50.173   919  2943 I Telecom : NewOutgoingCallIntentBroadcaster: Processing call intent in OutgoingCallIntentBroadcaster.: TSI.pC@AR8

03-14 11:04:50.173   919  2943 I Telecom : NewOutgoingCallIntentBroadcaster: processIntent isConferenceUri: false isSkipSchemaParsing = false: TSI.pC@AR8

03-14 11:04:50.180   919  2943 I Telecom : NewOutgoingCallIntentBroadcaster: Sending NewOutgoingCallBroadcast for [TC@1, CONNECTING, null, tel:*****, A, childs(0), has_parent(false), [Capabilities:], [Properties:]] to UserHandle{0}: TSI.pC@AR8

03-14 11:04:50.181   919  2943 I Telecom : NewOutgoingCallIntentBroadcaster: number = 10010 handle =  tel:10010: TSI.pC@AR8

03-14 11:04:50.181   919  2943 I Telecom : NewOutgoingCallIntentBroadcaster: Broadcasting intent: Intent { act=android.intent.action.NEW_OUTGOING_CALL flg=0x11000000 (has extras) }.: TSI.pC@AR8

03-14 11:04:50.181   919  2943 I Telecom : NewOutgoingCallIntentBroadcaster: No provider extras found in call intent.: TSI.pC@AR8

03-14 11:04:50.465   919   919 I Telecom : NewOutgoingCallBroadcastIntentReceiver: onReceive: Intent { act=android.intent.action.NEW_OUTGOING_CALL flg=0x11000010 (has extras) }: NOCBIR.oR@ASE

03-14 11:04:50.465   919   919 I Telecom : NewOutgoingCallBroadcastIntentReceiver: Received new-outgoing-call-broadcast for [TC@1, CONNECTING, null, tel:*****, A, childs(0), has_parent(false), [Capabilities:], [Properties:]] with data 10010: NOCBIR.oR@ASE

03-14 11:04:50.486   919   919 I Telecom : NewOutgoingCallIntentBroadcaster: Placing call immediately instead of waiting for OutgoingCallBroadcastReceiver: NOCBIR.oR@ASE

03-14 11:04:50.486   919   919 I Telecom : CallsManager: Creating a new outgoing call with handle: tel:*****: NOCBIR.oR@ASE

03-14 11:04:50.503   919   919 I Telecom : CreateConnectionProcessor: CreateConnectionProcessor created for Call = [TC@1, CONNECTING, null, tel:*****, A, childs(0), has_parent(false), [Capabilities:], [Properties:]]: NOCBIR.oR@ASE

03-14 11:04:50.503   919   919 I Telecom : CreateConnectionProcessor: process: NOCBIR.oR@ASE

03-14 11:04:50.514   919   919 I Telecom : CreateConnectionProcessor: attemptNextPhoneAccount: NOCBIR.oR@ASE

03-14 11:04:50.515   919   919 I Telecom : CreateConnectionProcessor: Trying attempt CallAttemptRecord(ComponentInfo{com.android.phone/com.android.services.telephony.TelephonyConnectionService}, ***, UserHandle{0},ComponentInfo{com.android.phone/com.android.services.telephony.TelephonyConnectionService}, ***, UserHandle{0}): NOCBIR.oR@ASE

03-14 11:04:50.528   919   919 I Telecom : : perform create connection: NOCBIR.oR->CSFM.rF@ASE

03-14 11:04:50.529   919   919 I Telecom : ConnectionServiceWrapper: createConnection([TC@1, CONNECTING, com.android.phone/com.android.services.telephony.TelephonyConnectionService, tel:*****, A, childs(0), has_parent(false), [Capabilities:], [Properties:]]) via ComponentInfo{com.android.phone/com.android.services.telephony.TelephonyConnectionService}.: NOCBIR.oR->CSFM.rF@ASE

03-14 11:04:50.529   919   919 I Telecom : ConnectionServiceWrapper: bind(): NOCBIR.oR->CSFM.rF@ASE

03-14 11:04:50.592   919   919 I Telecom : ServiceBinderConnection: Service bound ComponentInfo{com.android.phone/com.android.services.telephony.TelephonyConnectionService}: SBC.oSC@ASI

03-14 11:04:50.607   919   919 I Telecom : ConnectionServiceWrapper: Adding Connection Service Adapter.: SBC.oSC@ASI

03-14 11:04:50.611   919  2051 I Telecom : ConnectionServiceWrapper: ConnectionService -> Telecom[com.android.phone/com.android.services.telephony.TelephonyConnectionService]: queryRemoteConnectionServices com.android.internal.telecom.RemoteServiceCallback$Stub$Proxy@96c34a0: (...->CS.aCSA->H.CS.aCSA)->CSW.qRCS@E-E-ASI

  1. telecom层流程

    1. 模块简介

在去电的流程中,实质上这个模块只是一个中间人的作用,ConnectionService作为telephony中TelephonyConnectionService的父类,可以在telephony和telecom中做一个嫁接的作用。

  1. 流程分析

    1. 流程图
    1. 分析
  1. 这里主要是使用了一个handleMessage的机制,发送了一个MSG_CREATE_CONNECTION的消息
  2. 在handleMessage中对这个消息做了处理,然后调用createConnection方法
  3. 这个方法中会调用onCreateOutgoingConnection方法来创建一个Connection。但是我们发现ConnectionService类中的这个方法是没有做什么处理的,所以这里这个方法是在它的子类中重写的,调用的是TelephonyConnectionService中的onCreateOutgoingConnection方法。创建完毕会给这个链接设置一个callid,并调用addConnection方法去添加这个链接。
    1. 关键代码及log

      1. 关键代码
    1. ConnectionService.java

public void createConnection(

PhoneAccountHandle connectionManagerPhoneAccount,

String id,

ConnectionRequest request,

boolean isIncoming,

boolean isUnknown,

Session.Info sessionInfo) {

....................

//发送MSG_CREATE_CONNECTION消息

 mHandler.obtainMessage(MSG_CREATE_CONNECTION, args).sendToTarget();

} finally {

Log.endSession();

}

}

      1. ConnectionService.java

public void handleMessage(Message msg) {

switch (msg.what) {

..................................

case MSG_CREATE_CONNECTION: {

..........................

//调用createConnection方法

createConnection(

connectionManagerPhoneAccount,

id,

request,

isIncoming,

isUnknown);

.......................

}

      1. ConnectionService.java

private void createConnection(

final PhoneAccountHandle callManagerAccount,

final String callId,

final ConnectionRequest request,

boolean isIncoming,

boolean isUnknown) {

........................

Connection connection = null;

........................

//调用子类的onCreateOutgoingHandoverConnection方法来创建connection

connection = onCreateOutgoingHandoverConnection(fromPhoneAccountHandle, request);

........................

}

  1. 层流程

    1. 模块简介

在拨号的流程中,telephony用来创建Connection,在创建Connection的时候,需要先创建com.android.internal.telephony.Connection,然后去setOriginalConnection,将com.android.internal.telephony.Connection set到telecom的Connection中,实质上也是一个中间层的作用。

    1. 流程分析

      1. 流程图
      1. 分析

整个的telephony层并没有很多的流程,首先调用TelephonyConnectionService的onCreateOutgoingConnection方法,然后对这个连接做了一些判断,如果这里连接有问题就直接调用Connection.crelianjieateFailedConnection方法来上报一个错误的case。如果都没有问题,就对调用placeOutgoingConnection方法来准备拨号。最后会调用Phone类的dial方法。实质上调用的是Phone的子类的方法,例如GsmCdmaPhone的dial方法。

    1. 关键代码及log

03-14 11:04:50.644  1825  1825 I Telephony: TelephonyConnectionService: onCreateOutgoingConnection, request: ConnectionRequest xxxxxxxxx Bundle[{org.codeaurora.extra.CALL_DOMAIN=0, android.telecom.extra.START_CALL_WITH_VIDEO_STATE=0, android.telecom.extra.CALL_TELECOM_ROUTING_END_TIME_MILLIS=65560948, android.telecom.extra.CALL_CREATED_TIME_MILLIS=65560878, android.telecom.extra.CALL_TELECOM_ROUTING_START_TIME_MILLIS=65560947, com.android.dialer.callintent.CALL_SPECIFIC_APP_DATA=[B@6858ac0}]: (SBC.oSC)->CS.crCo->H.CS.crCo->H.CS.crCo.pICR@E-ASI

  1. Telephony层流程

    1. 模块简介

在拨号的流程中,这里是真正的去做拨号处理的,是涉及到和RIL层通信的。也就是说,这一层实质上是涉及到和网络层进行通信的,这里的东西大部分都是由telecom的同事来负责,app的同事对这一块可以稍微的模糊一点。

    1. 流程分析

      1. 流程图
      1. 分析
    1. 关键代码及log

Android去电流程相关推荐

  1. android去电流程,android 去电流程

    开始看代码. TwelveKeyDialer.java,既然要打电话,总要先输入号码才拨出,这个类就是拨号盘的界面,只是这个phone用到的类却是放在com.android.contacts包下,应该 ...

  2. Android 4.4 Kitkat Phone工作流程浅析(三)__MO(去电)流程分析

    本文来自http://blog.csdn.net/yihongyuelan 转载请务必注明出处 本文代码以MTK平台Android 4.4为分析对象,与Google原生AOSP有些许差异,请读者知悉. ...

  3. 去电流程分析---之一

    1,去电流程分析 1.1 app dialer 拨号盘界面有关拨号的部分由DialpadFragment.java实现,无论是单卡还是双卡,当点击拨号按键时,最后都会调用 handleDialButt ...

  4. Android绘制流程

    一.前言 1.1.C++界面库 MFC.WTL.DuiLib.QT.Skia.OpenGL. Android里面的画图分为2D和3D两种: 2D是由Skia 来实现的,3D部分是由OpenGL实现的. ...

  5. Android事件流程详解

    Android事件流程详解 网络上有不少博客讲述了android的事件分发机制和处理流程机制,但是看过千遍,总还是觉得有些迷迷糊糊,因此特地抽出一天事件来亲测下,向像我一样的广大入门程序员详细讲述an ...

  6. Android系统启动流程分析之安装应用

    2016六月 21 原 Android系统启动流程分析之安装应用 分类:Android系统源码研究 (295)  (0)  举报  收藏 跟随上一篇博客Android系统的启动流程简要分析继续分析an ...

  7. Android构建流程——篇二

    文章目录 预操作 任务列表 如何查看一个task类 Task1: checkDebugClasspath 1. input/output 2. 如何找到任务实现类 3. 核心类(AppClasspat ...

  8. Android构建流程——篇一

    Android构建流程 前言 APK 构建流程 AGP(3.2.0)任务列表总览图 参考文献 前言 大家平时开发Android项目时一般都是点击AS run按钮,这样apk会自动安装到手机上,这整个过 ...

  9. 详解 Android 系统启动流程

    系统启动流程大致分以下五步: Loader(加载引导程序Boot Loader) Kernel(Linux内核层) Native(init进程) Framework(Zygote进程/SystemSe ...

最新文章

  1. 与后台交互方法一 ——Ajax
  2. mysql complete_mysql 无意重启 [Note] /usr/sbin/mysqld: Normal shutdown
  3. js在for循环中绑定事件
  4. Android键盘面板冲突 布局闪动处理方案
  5. mysql 5.7 循环语句_MySQL循环语句|mysql|loop|delimiter|procedure|调用_网易订阅
  6. c#中程序以管理员身份运行的三种办法
  7. 中标麒麟linux卸载qt,国产化 银河麒麟编译Qt程序的问题汇总 | 阿拉灯
  8. click点击后鼠标移去就失效怎么实现_鼠标右键失灵怎么办,你知道原因吗?
  9. 好老婆的作息时间(做女人真悲哀 ……)
  10. 如何不用鼠标操作电脑
  11. 本人译著《Professional Xcode 3》现已翻译完毕
  12. JasperReport 导出PDF不能加载
  13. 用计算机关闭无线网络连接,干货分享:打印机无线连接断开了怎么办?
  14. 32位qt程序, 利用32位mysql驱动,连接64位mysql8.0
  15. Adobe Premiere基础-时间重映射(十)
  16. SAR/GMTI-概述及常用抑制杂波方法DPCA
  17. 后端修行 - java中PO、VO、BO、POJO、DAO、DTO、TO、QO的理解
  18. 【免费开放源码】审批类小程序项目实战(预约审批端)
  19. 什么是WAN?定义了广域网,示例以及它们的发展方向-ielab
  20. UCC27201DDAR

热门文章

  1. 3D点云基础知识(二)-bilibili视频资源整理(二)鞋点胶点云轮廓提取
  2. 用友软件T3数据库表结构表名、数据字典
  3. 项目立项管理-项目招投标工具技术:软件承建方投标综合成本评估法
  4. 使用git工具将项目上传到gitlab远程仓库
  5. 哪些网站可以发外链?分享几十个个可以发外链的网站
  6. 今天你在网上投简历了吗?
  7. 每日分享:Word如何翻译成中文
  8. python注销一段代码_请写出一段Python代码实现删除一个list里面的重复元素?
  9. 暗黑3服务器维护能登录,暗黑3登陆错误原因及解决办法详解
  10. Pandas提取数据的几种方式