1,去电流程分析

1.1 app dialer

拨号盘界面有关拨号的部分由DialpadFragment.java实现,无论是单卡还是双卡,当点击拨号按键时,最后都会调用

handleDialButtonPressed方法进行处理,调用流程图如下,

在handleDialButtonPressed方法中,首先进行号码的有效性检查,然后调用DialerUtils的startActivityWithErrorToast的方法进行处理,

final Intent intent = CallUtil.getCallIntent(number);
if (!isDigitsShown && !PhoneNumberUtils.isEmergencyNumber(number)) {// must be dial conference add extraintent.putExtra(EXTRA_DIAL_CONFERENCE_URI, true);
}
intent.putExtra(ADD_PARTICIPANT_KEY, mAddParticipant && isPhoneInUse());
if (subcription != INVALID_SUBSCRIPTION) {intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subcription);
}
DialerUtils.startActivityWithErrorToast(getActivity(), intent);
hideAndClearDialpad(false);//隐藏拨号盘

CallUtil的getCallIntent获取的intent,

final Intent intent = new Intent(Intent.ACTION_CALL, uri);

DialerUtils的startActivityWithErrorToast方法在此就是启动一个Activity,

context.startActivity(intent);

这样,在dialer进程中就处理完成了。

1.2 services telecom

telecom 中的AndroidManifest有关定义如下,

package="com.android.server.telecom"
coreApp="true"
android:sharedUserId="android.uid.system"

并且,在UserCallActivity下面,定义了intent-filter等信息,

<intent-filter><action android:name="android.intent.action.CALL" /><category android:name="android.intent.category.DEFAULT" /><data android:scheme="tel" />
</intent-filter>

因此, Intent.ACTION_CALL 会启动UserCallActivity,调用流程图如下,

UserCallActivity的onCreate方法如下,

new UserCallIntentProcessor(this, userHandle).processIntent(getIntent(),getCallingPackage(), true /* hasCallAppOp*/);

创建并调用UserCallIntentProcessor对象的processIntent方法,主要是一些检查,

if (!canCallNonEmergency && !TelephonyUtil.shouldProcessAsEmergency(mContext, handle)) {showErrorDialogForRestrictedOutgoingCall(mContext,R.string.outgoing_call_not_allowed_no_permission);Log.w(this, "Rejecting non-emergency phone call because "+ android.Manifest.permission.CALL_PHONE + " permission is not granted.");return;
}

检查完成之后,调用sendBroadcastToReceiver方法发送广播。

private boolean sendBroadcastToReceiver(Intent intent) {intent.putExtra(CallIntentProcessor.KEY_IS_INCOMING_CALL, false);intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);intent.setClass(mContext, PrimaryCallReceiver.class);Log.d(this, "Sending broadcast as user to CallReceiver");mContext.sendBroadcastAsUser(intent, UserHandle.OWNER);return true;
}

直接发送给PrimaryCallReceiver, 调用流程图如下,

onReceive方法如下,

public void onReceive(Context context, Intent intent) {synchronized (getTelecomSystem().getLock()) {getTelecomSystem().getCallIntentProcessor().processIntent(intent);}
}

getTelecomSystem方法如下,

public TelecomSystem getTelecomSystem() {return TelecomSystem.getInstance();
}

返回的是TelecomSystem对象, TelecomSystem也是一个单例,整个android系统中只有一个, TelecomSystem的

getCallIntentProcessor方法如下,

public CallIntentProcessor getCallIntentProcessor() {return mCallIntentProcessor;
}

返回的是CallIntentProcessor对象, CallIntentProcessor是在TelecomSystem的构造方法中构造的。

因此,最后调用的是CallIntentProcessor的processIntent方法,该方法如下,

if (isUnknownCall) {processUnknownCallIntent(mCallsManager, intent);
} else {processOutgoingCallIntent(mContext, mCallsManager, intent);
}

如果是未知号码如空号由processUnknownCallIntent方法处理

否则调用processOutgoingCallIntent方法,该方法主要逻辑如下,

1,从intent中获取各种参数,

Uri handle = intent.getData();
String scheme = handle.getScheme();
String uriString = handle.getSchemeSpecificPart();
•••

2,调用CallsManager的startOutgoingCall启动拨号界面,

Call call = callsManager.startOutgoingCall(handle, phoneAccountHandle, clientExtras);

3,调用NewOutgoingCallIntentBroadcaster的processIntent方法继续拨号,

NewOutgoingCallIntentBroadcaster broadcaster = new NewOutgoingCallIntentBroadcaster(context, callsManager, call, intent, isPrivilegedDialer);
final int result = broadcaster.processIntent();

拨号界面的启动后面再详细的论述。processIntent方法的调用流程图如下,

processIntent方法主要对三种类型call的一些检查,

普通call Intent.ACTION_CALL

系统call Intent.ACTION_CALL_PRIVILEGED

紧急呼叫call Intent.ACTION_CALL_EMERGENCY

普通call任何应用都可以发起,第三方应用拨号都是使用该intent

系统call只有系统应用才能使用

紧急呼叫call 同样只有系统应用才能使用,并且可以在无卡状态下拨号.

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;}
}
•••

最后调用broadcastIntent方法发送广播,

broadcastIntent(intent, number, !callImmediately);

broadcastIntent方法如下,

private void broadcastIntent(Intent originalCallIntent, String number, boolean receiverRequired) {Intent broadcastIntent = new Intent(Intent.ACTION_NEW_OUTGOING_CALL);if (number != null) {broadcastIntent.putExtra(Intent.EXTRA_PHONE_NUMBER, number);}// Force receivers of this broadcast intent to run at foreground priority because we// want to finish processing the broadcast intent as soon as possible.broadcastIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);Log.v(this, "Broadcasting intent: %s.", broadcastIntent);checkAndCopyProviderExtras(originalCallIntent, broadcastIntent);mContext.sendOrderedBroadcastAsUser(broadcastIntent, UserHandle.CURRENT,android.Manifest.permission.PROCESS_OUTGOING_CALLS,AppOpsManager.OP_PROCESS_OUTGOING_CALLS,receiverRequired ? new NewOutgoingCallBroadcastIntentReceiver() : null,null,  // schedulerActivity.RESULT_OK,  // initialCodenumber,  // initialData: initial value for the result data (number to be modified)null);  // initialExtras
}

直接发送给内部类NewOutgoingCallBroadcastIntentReceiver进行处理, onReceive方法又进行一系列检查,

最后调用CallsManager的placeOutgoingCall方法进行拨号,

mCallsManager.placeOutgoingCall(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));

真觉得这个内部类是多余的。

CallsManager的placeOutgoingCall方法会调用Call的startCreateConnection建立拨号连接,

startCreateConnection方法首先创建CreateConnectionProcessor对象,然后调用其process方法,

CreateConnectionProcessor的process方法调用流程图如下,

process方法会调用attemptNextPhoneAccount方法,在该方法中,首先获取ConnectionServiceWrapper对象,

然后调用createConnection方法建立连接,

PhoneAccountHandle phoneAccount = attempt.connectionManagerPhoneAccount;
ConnectionServiceWrapper service =  mRepository.getService(phoneAccount.getComponentName(),phoneAccount.getUserHandle());
if (service == null) {Log.i(this, "Found no connection service for attempt %s", attempt);attemptNextPhoneAccount();
} else {mCall.setConnectionManagerPhoneAccount(attempt.connectionManagerPhoneAccount);
mCall.setTargetPhoneAccount(attempt.targetPhoneAccount);
mCall.setConnectionService(service);
setTimeoutIfNeeded(service, attempt);service.createConnection(mCall, new Response(service));
}

mRepository是ConnectionServiceRepository对象,其getService方法如下,

ConnectionServiceWrapper getService(ComponentName componentName, UserHandle userHandle) {Pair<ComponentName, UserHandle> cacheKey = Pair.create(componentName, userHandle);ConnectionServiceWrapper service = mServiceCache.get(cacheKey);if (service == null) {service = new ConnectionServiceWrapper(componentName, this,mPhoneAccountRegistrar, mCallsManager, mContext, mLock, userHandle);service.addListener(mUnbindListener);mServiceCache.put(cacheKey, service);}return service;
}

在mServiceCache变量中找不到就创建ConnectionServiceWrapper对象,相当于一个本地的service管理。

ConnectionServiceWrapper继承于ServiceBinder,

ConnectionServiceWrapper的createConnection方法中,定义了BindCallback匿名类并且实现了onSuccess

和onFailure回调方法,并且调用了Binder2的bind方法,该方法如下,

mCallbacks.add(callback);//添加回调
if (mServiceConnection == null) {//连接未建立Intent serviceIntent = new Intent(mServiceAction).setComponent(mComponentName);ServiceConnection connection = new ServiceBinderConnection(call);Log.event(call, Log.Events.BIND_CS, mComponentName);final int bindingFlags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE;final boolean isBound;if (mUserHandle != null) {isBound = mContext.bindServiceAsUser(serviceIntent, connection, bindingFlags,mUserHandle);} else {isBound = mContext.bindService(serviceIntent, connection, bindingFlags);
}if (!isBound) {handleFailedConnection();return;}
} else {//连接已建立Log.d(ServiceBinder.this, "Service is already bound.");Preconditions.checkNotNull(mBinder);handleSuccessfulConnection();
}

如果未建立连接,会调用bindService绑定远程服务, mServiceAction和mComponentName变量都是在ServiceBinder的构造方法中赋值的,

ConnectionServiceWrapper的构造方法中会调用ServiceBinder的构造方法,

super(ConnectionService.SERVICE_INTERFACE, componentName, context, lock, userHandle);

ConnectionService的SERVICE_INTERFACE变量如下,

public static final String SERVICE_INTERFACE = "android.telecom.ConnectionService";

ConnectionService只是一个抽象类,具体的实现在services Telephony的TelephonyConnectionService中,并且

services Telephony的AndroidManifest关于TelephonyConnectionService有关定义如下,

<intent-filter><action android:name="android.telecom.ConnectionService" />
</intent-filter>

因此,绑定的就是TelephonyConnectionService服务。

当然,绑定失败的代码在此就不分析了,仅分析绑定成功的代码。

绑定成功之后, 就会回调ServiceBinder的内部类ServiceBinderConnection的onServiceConnected方法,

setBinder(binder); //获取远程服务的binder
handleSuccessfulConnection();//回调方法

setBinder方法会调用ConnectionServiceWrapper的setServiceInterface方法,如下,

mServiceInterface = IConnectionService.Stub.asInterface(binder);
addConnectionServiceAdapter(mAdapter);

为mServiceInterface变量赋值,这样mServiceInterface就指向远程的TelephonyConnectionService对象。

ServiceBinder的handleSuccessfulConnection方法如下,

private void handleSuccessfulConnection() {for (BindCallback callback : mCallbacks) {callback.onSuccess();}mCallbacks.clear();
}

回调createConnection方法中的callback的onSuccess方法,

mServiceInterface.createConnection(call.getConnectionManagerPhoneAccount(),callId, new ConnectionRequest(call.getTargetPhoneAccount(),call.getHandle(),extras,call.getVideoState()),call.isIncoming(),call.isUnknown());

这样,就会调用TelephonyConnectionService的createConnection方法。

创建连接实际上就是创建services telecom 到 services Telephony的一个连接。

这样, services telecom中的流程也处理完成了。

去电流程分析---之一相关推荐

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

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

  2. Linphone android去电增加自定义SIP消息头的流程分析

    一.首先看一下如何在发起去电的sip请求中添加自定义的消息头 增加自定义头消息发方法,so已经提供了native方法, 发起呼叫的示例如下: LinphoneCallParams params = l ...

  3. Android5.1 Telecomm层通话去电流程两路进程分析之一通话去电流程框架介绍

    1.1 通话去电流程框架介绍 概述:Android5.1相对于以往的平台对通话功能做了很大程度上的修改,在这里,差异性我们到最后去分析,我们先看通话去电的大概结构,在这之前我先提出几点疑问,比如通话过 ...

  4. Android7.0 Phone应用源码分析(二) phone来电流程分析

    当有来电通知时,首先接收到消息的是Modem层,然后Medoem再上传给RIL层,RIL进程通过sokcet将消息发送给RILJ(framework层的RIL),同样进入RILJ的processRes ...

  5. Android去电流程

    Version:1.0 StartHTML:0000000174 EndHTML:0000527746 StartFragment:0000129196 EndFragment:0000527706 ...

  6. 安卓手机来电亮屏流程分析

    来电亮屏流程分析 本文档是针对手机来电时候自主点亮屏幕这一流程的分析,很自然的就将其分为2个阶段,第一个是来电,第二个是点亮屏幕. 来电的流程: 来电消息是从RIL层接收到的,然后才开始传递上来. A ...

  7. Linphone-android 登录过程增加自定义消息头流程分析

    注册增加消息头 在saveNewAccount()中: 添加自定义消息头 LinphoneProxyConfig prxCfg = lc.createProxyConfig(identityAddr. ...

  8. VLC架构及流程分析

    0x00 前置信息 VLC是一个非常庞大的工程,我从它的架构及流程入手进行分析,涉及到一些很细的概念先搁置一边,日后详细分析. 0x01 源码结构(Android Java相关的暂未分析) # bui ...

  9. 动态执行流程分析和性能瓶颈分析的利器——gperftools的Cpu Profiler

    在<动态执行流程分析和性能瓶颈分析的利器--valgrind的callgrind>中,我们领略了valgrind对流程和性能瓶颈分析的强大能力.本文将介绍拥有相似能力的gperftools ...

最新文章

  1. 丘维声高等代数pdf_2020年兰州大学高等代数真题出处简直惊讶
  2. 《精通Nginx》——1.2 从源代码安装Nginx
  3. vue-cli4.0打包之后,页面空白,路由404
  4. 20165223 week2测试补交与总结
  5. 27款经典的 CSS 框架分享
  6. 经验总结:完整做完一款游戏需要经历哪些流程?
  7. linux火狐怎么切换到ie内核,如何切换浏览器火狐 FIREFOX和IE之间切换
  8. MATLAB-数组的使用
  9. PS如何快速更换logo颜色
  10. 计算机英文电子书分享
  11. 无线手柄在ROS上的使用
  12. 《大江大河2》里的创业故事
  13. java画篮球_PS教程!手把手教你绘制炫酷的科比篮球海报
  14. Flutter 快速上手定时器/倒计时及实战讲解
  15. 2022年下半年网络工程师上午综合知识真题答案解析
  16. simulink实现ESO(扩张状态观测器)
  17. 格鲁伯小升初文学常识必考
  18. B站黑马程序员Oracle学习——项目案例:送水公司收费系统
  19. dbeaver替换Navicat后某些网络无法连接问题解决
  20. oracle 云计算业务,拉里.埃里森:Oracle云计算服务进入超速增长阶段

热门文章

  1. python自带的框架是什么_Python Django框架是什么?Python学习入门!
  2. Android 热修复 Tinker接入及源码浅析最精彩没有之一
  3. 零基础HTML入门教程(23)--HTML综合实例
  4. 百威系统数据库服务器,百威9000V6数据库日志文件太大怎么清理?
  5. 快手小程序研发总结页面跳转参数携带需注意
  6. CSS - 网格布局(grid)
  7. 我不是英雄:是他干掉了WannaCry的域名开关
  8. Lightoj 1062 Crossed Ladders (二分)
  9. 百度和 Google 的搜索技术是一个量级吗?
  10. Jpcap简介(转)