Android去电流程
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
- 简介
- 概述
此文档详细的介绍了android中的去电流程,一直从上层(dialer)到底层(RIL)层的详细流程,可以让相关的同事在解决去电问题的时候快速的定位问题点,方便了bug的fix。
- 适用范围
此问题使用了android P平台,高通和MTK均适用。
- 详细流程图
- 层流程
- 模块简介
- 概述
- 模块简介
手机最基本的功能包括两个大的方面,一个是打电话功能,一个是短信功能,我们这里的Dialer模块指的就是打电话功能的一部分,他是手机与用户交互的桥梁,提供图形界面来给用户操作,使用户能够通过一系列的操作拨打电话等等。
从源码的包的命名,可以将Dialer分为四个大的部分,包含:contact、incallui、dialer、voicemial。Contact主要是联系人相关的逻辑,与Contact模块有着很大的联系;incallui主要是通话过程中的incall界面的东西,在通话过程中,设计到很多的与底层交与的逻辑,需要调用底层的接口来获取电话状态并显示在incall界面上,需要调用底层接口来对call进行操作;dialer主要是点击app图标进入之后的界面的显示、界面相关操作的逻辑以及一部分dialer的设置;voicemial是voicemail相关的代码,调用的是底层的接口。
- 流程分析
- 关键代码及log
这一个部分代码逻辑较为简单,且代码中没有打印关键log,所以这一部分就不贴关键代码以及关键log,只要关注上一个部分的流程就可以。
- 层流程
- 模块简介
- 概述
- 模块简介
这里的Telecom层指的是位于packages/services/Telecomm的模块,是android 5.0之后从phone进程中提出来的位于incallui(也就是dialer进程)和phone进程(telephony)之间的模块,运行于系统进程之中。基本上所有的incallui界面上的显示相关的信息都是从这个模块中调用接口获取而来的,而这个模块实质上是没有和底层打交道的,他上面链接dialer,下面链接的是framework/base/telecom,所以可以把他看做是一个中间层的接口,涉及到底层的东西是没有放在这里处理的。
实际上,在这个模块中,我认为最最重要的需要我们来关注的类,就是TelecomServiceImpl.java,基本上所有的call相关的重要方法,都是放在这个类中来实现的。
- 流程分析
- 流程图
- 分析
- 检查一些权限相关的东西,然后创建一个UserCallIntentProcessor,调用它的processIntent方法。
- 从intent中取出action,判断action是否等于ACTION_CALL||ACTION_CALL_PRIVILEGED||ACTION_CALL_EMERGENCY。如果相等,调用processOutgoingCallIntent方法
- 对号码的uri做了以下处理,判断传入的正在拨号的dialer是不是默认dialer,存入intent中(CallIntentProcessor.KEY_IS_PRIVILEGED_DIALER)。然后调用sendIntentToDestination方法
- 在这个方法中会判断isLocalInvocation,这个参数是从TelecomServiceImpl中的placeCall方法传过来的,默认是true。如果是false,就会发送广播到PrimaryCallReceiver,然后调用CallIntentProcessor的processIntent方法。如果是true,则会直接调用CallIntentProcessor的processIntent方法,这样就省去了中间的广播接受时间,性能更加优异。
- 在processIntent方法中,从intent中判断KEY_IS_UNKNOWN_CALL是否是true,如果是,则调用processUnknownCallIntent方法,如果不是,调用processOutgoingCallIntent方法。
- 对号码的uri进行处理,判断是sip号码还是普通号码,添加上scheme,将call相关的信息封装到Bundle中,然后调用callsmanager的startOutgoingCall方法。
- 在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。
- 创建一个NewOutgoingCallIntentBroadcaster对象,调用他的processIntent方法。这个方法是有返回值的,如果返回值不等于DisconnectCause.NOT_DISCONNECTED,那么就会在这里挂断电话并弹出提示框提示。
- 在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方法来拨打电话。
- 在broadcastIntent方法中,调用sendOrderedBroadcastAsUser方法发送了广播。
- NewOutgoingCallIntentBroadcast的onReceive方法接收到这个广播,最后还是调用placeOutgoingCallImmediately方法来拨打电话。
- 在placeOutgoingCallImmediately方法中,将call的mIsNewOutgoingCallIntentBroadcastDone参数设置为了true,表示NewOutgoingCallIntentBroadcast完毕,接着调用callsmanager的placeOutgoingCall方法。
- 在callsmanager的placeOutgoingCall方法中,会检查是否需要打开扬声器,如果需要会打开扬声器。然后调用call的startCreateConnection方法去创建Connection。
- startCreateConnection方法中创建了一个CreateConnectionProcessor对象,然后调用它的process方法。
- 向mAttemptRecords中加入当前电话的CallAttemptRecord对象,实质上就是两个PhoneAccountHandle对象。然后调用attemptNextPhoneAccount方法。
- 在attemptNextPhoneAccount方法中,首先会判断mAttemptRecords列表中的PhoneAccountHandle是否具有BIND_TELECOM_CONNECTION_SERVICE权限,判断是否能够绑定链接,然后调用ConnectionServiceRepository的getService()方法得到mService,而mService是一个ConnectionServiceWrapper类的实例对象,我们可以把ConnectionServiceWrapper看做是一个代理类,因为其父类ServiceBinder是一个抽象类,且绑定了一个远程服务,然后调用ConnectionServiceWrapper.java的createConnection方法。
- 在createConnection方法中,会创建一个BindCallback对象,实现它的onSuccess和onFailure方法,创建完毕之后,会调用mBinder.bind(callback, call)方法去绑定,如果绑定成功,就会回调BindCallback的onSuccess方法 。
- 关键代码及log
- 关键代码
- 关键代码及log
- 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 */); ...................... } |
- 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); } } |
- UserCallIntentProcessor.java
private void processOutgoingCallIntent(Intent intent, String callingPackageName, boolean canCallNonEmergency, boolean isLocalInvocation) { .................................. //调用sendIntentToDestination方法来准备发送广播 sendIntentToDestination(intent, isLocalInvocation); .................................. } |
- 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; } |
- 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); } } |
- 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(在InCallController的onCallAdded方法中回去调用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); |
- CallIntentProcessor.java
static void processOutgoingCallIntent( Context context, CallsManager callsManager, Intent intent) { .................................. //对call对象做判空处理,不为空时调用sendNewOutgoingCallIntent方法继续拨号流程 if (call != null) { sendNewOutgoingCallIntent(context, call, callsManager, intent); } } |
- 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(); ............................ } |
- 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; } |
- 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 } |
- 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)); .............................. } |
- 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); } |
- 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); ............................ } |
- Call.java
void startCreateConnection(PhoneAccountRegistrar phoneAccountRegistrar) { //创建一个CreateConnectionProcessor对象,这个对象用来创建outgoingcall的链接和incomingcall的连接 mCreateConnectionProcessor = new CreateConnectionProcessor(this, mRepository, this, phoneAccountRegistrar, mContext); //实例化完毕调用他的process方法 mCreateConnectionProcessor.process(); } |
- 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(); } |
- 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); } } |
- 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); } |
- 关键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 |
- telecom层流程
- 模块简介
在去电的流程中,实质上这个模块只是一个中间人的作用,ConnectionService作为telephony中TelephonyConnectionService的父类,可以在telephony和telecom中做一个嫁接的作用。
- 流程分析
- 流程图
- 分析
- 这里主要是使用了一个handleMessage的机制,发送了一个MSG_CREATE_CONNECTION的消息
- 在handleMessage中对这个消息做了处理,然后调用createConnection方法
- 这个方法中会调用onCreateOutgoingConnection方法来创建一个Connection。但是我们发现ConnectionService类中的这个方法是没有做什么处理的,所以这里这个方法是在它的子类中重写的,调用的是TelephonyConnectionService中的onCreateOutgoingConnection方法。创建完毕会给这个链接设置一个callid,并调用addConnection方法去添加这个链接。
- 关键代码及log
- 关键代码
- ConnectionService.java
- 关键代码及log
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(); } } |
- ConnectionService.java
public void handleMessage(Message msg) { switch (msg.what) { .................................. case MSG_CREATE_CONNECTION: { .......................... //调用createConnection方法 createConnection( connectionManagerPhoneAccount, id, request, isIncoming, isUnknown); ....................... } |
- 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); ........................ } |
- 层流程
- 模块简介
在拨号的流程中,telephony用来创建Connection,在创建Connection的时候,需要先创建com.android.internal.telephony.Connection,然后去setOriginalConnection,将com.android.internal.telephony.Connection set到telecom的Connection中,实质上也是一个中间层的作用。
- 流程分析
- 流程图
- 流程分析
- 分析
整个的telephony层并没有很多的流程,首先调用TelephonyConnectionService的onCreateOutgoingConnection方法,然后对这个连接做了一些判断,如果这里连接有问题就直接调用Connection.crelianjieateFailedConnection方法来上报一个错误的case。如果都没有问题,就对调用placeOutgoingConnection方法来准备拨号。最后会调用Phone类的dial方法。实质上调用的是Phone的子类的方法,例如GsmCdmaPhone的dial方法。
- 关键代码及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 |
- Telephony层流程
- 模块简介
在拨号的流程中,这里是真正的去做拨号处理的,是涉及到和RIL层通信的。也就是说,这一层实质上是涉及到和网络层进行通信的,这里的东西大部分都是由telecom的同事来负责,app的同事对这一块可以稍微的模糊一点。
- 流程分析
- 流程图
- 流程分析
- 分析
- 关键代码及log
Android去电流程相关推荐
- android去电流程,android 去电流程
开始看代码. TwelveKeyDialer.java,既然要打电话,总要先输入号码才拨出,这个类就是拨号盘的界面,只是这个phone用到的类却是放在com.android.contacts包下,应该 ...
- Android 4.4 Kitkat Phone工作流程浅析(三)__MO(去电)流程分析
本文来自http://blog.csdn.net/yihongyuelan 转载请务必注明出处 本文代码以MTK平台Android 4.4为分析对象,与Google原生AOSP有些许差异,请读者知悉. ...
- 去电流程分析---之一
1,去电流程分析 1.1 app dialer 拨号盘界面有关拨号的部分由DialpadFragment.java实现,无论是单卡还是双卡,当点击拨号按键时,最后都会调用 handleDialButt ...
- Android绘制流程
一.前言 1.1.C++界面库 MFC.WTL.DuiLib.QT.Skia.OpenGL. Android里面的画图分为2D和3D两种: 2D是由Skia 来实现的,3D部分是由OpenGL实现的. ...
- Android事件流程详解
Android事件流程详解 网络上有不少博客讲述了android的事件分发机制和处理流程机制,但是看过千遍,总还是觉得有些迷迷糊糊,因此特地抽出一天事件来亲测下,向像我一样的广大入门程序员详细讲述an ...
- Android系统启动流程分析之安装应用
2016六月 21 原 Android系统启动流程分析之安装应用 分类:Android系统源码研究 (295) (0) 举报 收藏 跟随上一篇博客Android系统的启动流程简要分析继续分析an ...
- Android构建流程——篇二
文章目录 预操作 任务列表 如何查看一个task类 Task1: checkDebugClasspath 1. input/output 2. 如何找到任务实现类 3. 核心类(AppClasspat ...
- Android构建流程——篇一
Android构建流程 前言 APK 构建流程 AGP(3.2.0)任务列表总览图 参考文献 前言 大家平时开发Android项目时一般都是点击AS run按钮,这样apk会自动安装到手机上,这整个过 ...
- 详解 Android 系统启动流程
系统启动流程大致分以下五步: Loader(加载引导程序Boot Loader) Kernel(Linux内核层) Native(init进程) Framework(Zygote进程/SystemSe ...
最新文章
- 与后台交互方法一 ——Ajax
- mysql complete_mysql 无意重启 [Note] /usr/sbin/mysqld: Normal shutdown
- js在for循环中绑定事件
- Android键盘面板冲突 布局闪动处理方案
- mysql 5.7 循环语句_MySQL循环语句|mysql|loop|delimiter|procedure|调用_网易订阅
- c#中程序以管理员身份运行的三种办法
- 中标麒麟linux卸载qt,国产化 银河麒麟编译Qt程序的问题汇总 | 阿拉灯
- click点击后鼠标移去就失效怎么实现_鼠标右键失灵怎么办,你知道原因吗?
- 好老婆的作息时间(做女人真悲哀 ……)
- 如何不用鼠标操作电脑
- 本人译著《Professional Xcode 3》现已翻译完毕
- JasperReport 导出PDF不能加载
- 用计算机关闭无线网络连接,干货分享:打印机无线连接断开了怎么办?
- 32位qt程序, 利用32位mysql驱动,连接64位mysql8.0
- Adobe Premiere基础-时间重映射(十)
- SAR/GMTI-概述及常用抑制杂波方法DPCA
- 后端修行 - java中PO、VO、BO、POJO、DAO、DTO、TO、QO的理解
- 【免费开放源码】审批类小程序项目实战(预约审批端)
- 什么是WAN?定义了广域网,示例以及它们的发展方向-ielab
- UCC27201DDAR