[CS] 拨号流程


Platform:Android-7.1.1_r22

CS Call拨号请求流程


为了更清楚的了解整个拨号请求的流程,所以将App部分的代码也简单梳理了一下。

先从Dialer开始,按下拨号盘的Dial键后,会触发:

com.android.dialer.dialpad.DialpadFragment.java

public void onClick(View view) {
......
if (resId == R.id.dialpad_floating_action_button) {
// 处理Dial_button被按下的事件
view.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
handleDialButtonPressed();
......
}

处理拨号事件时,会将号码打包到Intent,启动新的任务处理,并退出当前Activity。

private void handleDialButtonPressed() {
if (isDigitsEmpty()) { // No number entered.
......
} else {
......
if (number != null
&& !TextUtils.isEmpty(mProhibitedPhoneNumberRegexp)
&& number.matches(mProhibitedPhoneNumberRegexp)) {
// 号码受限
......
} else {
// 正常拨号
final Intent intent = new CallIntentBuilder(number).
setCallInitiationType(LogState.INITIATION_DIALPAD)
.build(); // Action会被设置为Intent.ACTION_CALL
DialerUtils.startActivityWithErrorToast(getActivity(), intent);
hideAndClearDialpad(false);
}
}
}

准备启动新的Activity来处理拨号。

DialerUtils.java

public static void startActivityWithErrorToast(Context context, Intent intent) {
startActivityWithErrorToast(context, intent, R.string.activity_not_available);
}

public static void startActivityWithErrorToast(Context context, Intent intent, int msgId) {
try {
if ((IntentUtil.CALL_ACTION.equals(intent.getAction())
&& context instanceof Activity)) {
......
final boolean hasCallPermission = TelecomUtil.placeCall((Activity) context, intent);
......
} else {
......
}

TelecomUtil中会判断拨号的Activity是否有CALL_PHONE的权限,若有,则继续,若无,则返回。

TelecomUtil.java
public static boolean placeCall(Activity activity, Intent intent) {
if (hasCallPhonePermission(activity)) {
TelecomManagerCompat.placeCall(activity, getTelecomManager(activity), intent);
return true;
}
return false;
}

TelecomManagerCompat中会根据不同的Android版本执行不同的流程。

TelecomManagerCompat.java
public static void placeCall(@Nullable Activity activity,
@Nullable TelecomManager telecomManager, @Nullable Intent intent) {
if (activity == null || telecomManager == null || intent == null) {
return;
}
if (CompatUtils.isMarshmallowCompatible()) {
// AndroidM及以上版本流程,只会吧Intent的uri和extras传递下去
telecomManager.placeCall(intent.getData(), intent.getExtras());
return;
}
// AndroidM以下版本流程
activity.startActivityForResult(intent, 0);
}

我们这里只分析AndroidM及以上版本的流程。
TelecomManager为App提供了访问active call、注册、呼叫管理等接口。
TelecomManager.java

public void placeCall(Uri address, Bundle extras) {
ITelecomService service = getTelecomService();
if (service != null) {
......
// 通过Binder调到TelecomServiceImpl.mBinderImpl
service.placeCall(address, extras == null ? new Bundle() : extras,
mContext.getOpPackageName());
......
}


在ITelecomService中继续处理拨号请求。
TelecomServiceImpl.java

private final ITelecomService.Stub mBinderImpl = new ITelecomService.Stub() {
......
public void placeCall(Uri handle, Bundle extras, String callingPackage) {
......
try {
// 又把uri和extras组装成Intent,为啥拆了又装回去啊啊啊啊啊????
final Intent intent = new Intent(Intent.ACTION_CALL, handle);
......
// 调用UserCallIntentProcessor的processIntent()
mUserCallIntentProcessorFactory.create(mContext, userHandle)
.processIntent(
intent, callingPackage, hasCallAppOp && hasCallPermission);
} finally {
......
}
......
}


UserCallIntentProcessor.java
先通过读取config_voice_capable的值判断设备是否支持语音通话,如果不支持的话就直接return了。
public void processIntent(Intent intent, String callingPackageName,
boolean canCallNonEmergency) {
// Ensure call intents are not processed on devices that are not capable of calling.
if (!isVoiceCapable()) {
return; // 不支持语音通话
}
......
// 此处action为ACTION_CALL
if (Intent.ACTION_CALL.equals(action) ||
Intent.ACTION_CALL_PRIVILEGED.equals(action) ||
Intent.ACTION_CALL_EMERGENCY.equals(action)) {
processOutgoingCallIntent(intent, callingPackageName, canCallNonEmergency);
}
}

这里面会先检查是否有权限拨号,若有,则会发送广播进行下一步处理。
private void processOutgoingCallIntent(Intent intent, String callingPackageName,
boolean canCallNonEmergency) {
......
if (!UserUtil.isManagedProfile(mContext, mUserHandle)) {

// 如果不是managed profile user,那么将检查其是否被允许打电话(紧急呼不做检查,始终允许)
// 如果不允许,则返回

......
}

if (!canCallNonEmergency && !TelephonyUtil.shouldProcessAsEmergency(mContext, handle)) {
showErrorDialogForRestrictedOutgoingCall(mContext,
R.string.outgoing_call_not_allowed_no_permission);

// 没有android.Manifest.permission.CALL_PHONE的权限
Log.w(this, "Rejecting non-emergency phone call because "
+ android.Manifest.permission.CALL_PHONE + " permission is not granted.");
return;
}

......
sendBroadcastToReceiver(intent);
}

private boolean sendBroadcastToReceiver(Intent intent) {
......
intent.setClass(mContext, PrimaryCallReceiver.class);
......
mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM);
return true;
}


PrimaryCallReceiver.java
收到广播后并没有做什么处理,直接交由CallIntentProcessor继续处理。
public void onReceive(Context context, Intent intent) {
Log.startSession("PCR.oR");
synchronized (getTelecomSystem().getLock()) {
getTelecomSystem().getCallIntentProcessor().processIntent(intent);
}
Log.endSession();
}


CallIntentProcessor.java
public void processIntent(Intent intent) {
......
// 不是unknown call
if (isUnknownCall) {
processUnknownCallIntent(mCallsManager, intent);
} else {
processOutgoingCallIntent(mContext, mCallsManager, intent);
}
......
}

处理CALL、CALL_PRIVILEGED以及CALL_EMERGENCY的intent。
会建立一个com.android.server.telecom.Call对象,然后在交由NewOutgoingCallIntentBroadcaster处理。
static void processOutgoingCallIntent(
Context context,
CallsManager callsManager,
Intent intent) {
......
Call call = callsManager
.startOutgoingCall(handle, phoneAccountHandle, clientExtras, initiatingUser);

if (call != null) {
......
NewOutgoingCallIntentBroadcaster broadcaster = new NewOutgoingCallIntentBroadcaster(
context, callsManager, call, intent, callsManager.getPhoneNumberUtilsAdapter(),
isPrivilegedDialer);
final int result = broadcaster.processIntent();
......
}
}

NewOutgoingCallIntentBroadcaster.java

public int processIntent() {
......
// 对于非紧急号码,ACTION_CALL_PRIVILEGED会被转换为ACTION_CALL
rewriteCallIntentAction(intent, isPotentialEmergencyNumber);
action = intent.getAction();
......

broadcastIntent(intent, number, !callImmediately, targetUser);
return DisconnectCause.NOT_DISCONNECTED;
}

发送一个新的广播,以便第三方app能够先进行一些处理,如取消拨号、重定向号码等。
bu
private void broadcastIntent(
Intent originalCallIntent,
String number,
boolean receiverRequired,
UserHandle targetUser) {
Intent broadcastIntent = new Intent(Intent.ACTION_NEW_OUTGOING_CALL);
......
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
}

广播经由其他receiver处理后,最终又回到NewOutgoingCallBroadcastIntentReceiver进行处理。
这里面会根据其他receiver的处理结果判断是否继续拨号。
public class NewOutgoingCallBroadcastIntentReceiver extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {
......
// 判断是否继续拨号, 略...
......
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.java
接下来到了CallsManager,尝试去连接指定的call。
public void placeOutgoingCall(Call call, Uri handle, GatewayInfo gatewayInfo,
boolean speakerphoneOn, int videoState) {
......
if (call.getTargetPhoneAccount() != null || call.isEmergencyCall()) {
......
call.startCreateConnection(mPhoneAccountRegistrar);
......
}


com.android.server.telecom.Call.java
开始建立connection。
void startCreateConnection(PhoneAccountRegistrar phoneAccountRegistrar) {
......
mCreateConnectionProcessor = new CreateConnectionProcessor(this, mRepository, this,
phoneAccountRegistrar, mContext);
mCreateConnectionProcessor.process();
}

CreateConnectionProcessor会建立一个connection用于新的outgoing call。
CreateConnectionProcessor.java

public void process() {
......
attemptNextPhoneAccount();
}

查找具有BIND_TELECOM_CONNECTION_SERVICE权限的PhoneAccount。
private void attemptNextPhoneAccount() {
......
if (mCallResponse != null && attempt != null) {
......
mService = mRepository.getService(phoneAccount.getComponentName(),
phoneAccount.getUserHandle());
if (mService == null) {
......
} else {
......
mService.createConnection(mCall, this);
}
......
}


ConnectionServiceWrapper.java
为outgoing call建立一个新的connection。
public void createConnection(final Call call, final CreateConnectionResponse response) {
......
BindCallback callback = new BindCallback() {
@Override
public void onSuccess() {
// 此方法会在绑定service成功后调用,稍后再分析
......
}
......
};
// 绑定service
mBinder.bind(callback, call);
}

ServiceBinder.java
绑定到TelephonyConnectionService,这也预示着即将进入TelephonyService的流程了。
final class Binder2 {

void bind(BindCallback callback, Call call) {
......
mCallbacks.add(callback);
if (mServiceConnection == null) {
// mComponentName对应的class为TelephonyConnectionService
Intent serviceIntent = new Intent(mServiceAction).setComponent(mComponentName);
ServiceConnection connection = new ServiceBinderConnection(call);
......
if (mUserHandle != null) {
isBound = mContext.bindServiceAsUser(serviceIntent, connection, bindingFlags,
mUserHandle);
} else {
isBound = mContext.bindService(serviceIntent, connection, bindingFlags);
}
......
} else {
......
}
}
}

绑定成功后回调onServiceConnected()
private final class ServiceBinderConnection implements ServiceConnection {

public void onServiceConnected(ComponentName componentName, IBinder binder) {
......
setBinder(binder);
handleSuccessfulConnection();
......
}

}

先来看看setBinder()的流程。
private void setBinder(IBinder binder) {
if (mBinder != binder) {
if (binder == null) {
......
} else {
mBinder = binder;
setServiceInterface(binder);
}
}
}

ConnectionServiceWrapper.java
protected void setServiceInterface(IBinder binder) {
mServiceInterface = IConnectionService.Stub.asInterface(binder);
......
addConnectionServiceAdapter(mAdapter);
}

private void addConnectionServiceAdapter(IConnectionServiceAdapter adapter) {
......
mServiceInterface.addConnectionServiceAdapter(adapter);
......
}

通过Binder方式调到了ConnectionService
ConnectionService.java
private final IBinder mBinder = new IConnectionService.Stub() {
@Override
public void addConnectionServiceAdapter(IConnectionServiceAdapter adapter) {
mHandler.obtainMessage(MSG_ADD_CONNECTION_SERVICE_ADAPTER, adapter).sendToTarget();
}
}

private final Handler mHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_ADD_CONNECTION_SERVICE_ADAPTER:
mAdapter.addAdapter((IConnectionServiceAdapter) msg.obj);
onAdapterAttached();
break;
......
}
}

private void onAdapterAttached() {
......
// 这里不大清楚是在查询啥,不过查询成功后肯定是要调onResult()的
mAdapter.queryRemoteConnectionServices(new RemoteServiceCallback.Stub() {
@Override
public void onResult(
final List<ComponentName> componentNames,
final List<IBinder> services) {
mHandler.post(new Runnable() {
@Override
public void run() {
......
onAccountsInitialized();
......
}
});
}
......
});
}

这里会先将mAreAccountsInitialized设为true,表示Account已经初始化完了,之后再进行回调。
至于回调到什么地方,后面会有说明。
private void onAccountsInitialized() {
mAreAccountsInitialized = true;
for (Runnable r : mPreInitializationConnectionRequests) {
r.run();
}
mPreInitializationConnectionRequests.clear();
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

看完setBinder()的流程,接下来就是handleSuccessfulConnection()的流程了。
还是继续回调,在Binder2.bind()中,我们将callback加入到了mCallbacks。
private void handleSuccessfulConnection() {
for (BindCallback callback : mCallbacks) {
callback.onSuccess();
}
mCallbacks.clear();
}

于是,最终就回调到了ConnectionServiceWrapper.createConnection()中的callback。
BindCallback callback = new BindCallback() {
@Override
public void onSuccess() {
String callId = mCallIdMapper.getCallId(call);
mPendingResponses.put(callId, response);
......
try {
mServiceInterface.createConnection(
......
call.isUnknown());
} catch (RemoteException e) {
......
}
}

};

接下来就进入TelephonyService的流程了。
首先就是建立Connection。

ConnectionService.java
private final IBinder mBinder = new IConnectionService.Stub() {
public void createConnection(
......
boolean isUnknown) {
......
mHandler.obtainMessage(MSG_CREATE_CONNECTION, args).sendToTarget();
}
}

在前面Account初始化完成后,在mAreAccountsInitialized设置为了true,所以当运行到下面代码时,
若mAreAccountsInitialized为true,那么就直接调用createConnection()方法,
若mAreAccountsInitialized为false,就将createConnection()封装到Runnable中,待Account初始化完成后,
通过回调来执行createConnection()方法。

private final Handler mHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
......
case MSG_CREATE_CONNECTION: {
......
if (!mAreAccountsInitialized) {
......
mPreInitializationConnectionRequests.add(new Runnable() {
@Override
public void run() {
createConnection(
......
isUnknown);
}
});
} else {
createConnection(
......
isUnknown);
}
......
}
}

开始建立Outgoing的Connection,建立完成后还会进行一些处理。
private void createConnection(
......
boolean isUnknown) {
......
Connection connection = isUnknown ? onCreateUnknownConnection(callManagerAccount, request)
: isIncoming ? onCreateIncomingConnection(callManagerAccount, request)
: onCreateOutgoingConnection(callManagerAccount, request);
......
mAdapter.handleCreateConnectionComplete(
......
connection.getExtras()));
......
}

先来看看outgoing连接建立完成后的处理。
ConnectionServiceAdapter.java
通过回调调到ConnectionServiceWrapper.Adapter中去。
void handleCreateConnectionComplete(
......
ParcelableConnection connection) {
for (IConnectionServiceAdapter adapter : mAdapters) {
......
adapter.handleCreateConnectionComplete(id, request, connection);
......
}
}

ConnectionServiceWrapper.java

private final class Adapter extends IConnectionServiceAdapter.Stub {

@Override
public void handleCreateConnectionComplete(String callId, ConnectionRequest request,
ParcelableConnection connection) {
......
ConnectionServiceWrapper.this
.handleCreateConnectionComplete(callId, request, connection);
......
}
}

private void handleCreateConnectionComplete(
......
ParcelableConnection connection) {
......
if (connection.getState() == Connection.STATE_DISCONNECTED) {
......
} else {
// Successful connection
if (mPendingResponses.containsKey(callId)) {
mPendingResponses.remove(callId)
.handleCreateConnectionSuccess(mCallIdMapper, connection);
}
}
}

最终来到Call中,这里面会通过回调的方式把一些连接状态通知给相应的监听者。
com.android.server.telecom.Call.java

public void handleCreateConnectionSuccess(
CallIdMapper idMapper,
ParcelableConnection connection) {
Log.v(this, "handleCreateConnectionSuccessful %s", connection);
setTargetPhoneAccount(connection.getPhoneAccount());
setHandle(connection.getHandle(), connection.getHandlePresentation());
setCallerDisplayName(
connection.getCallerDisplayName(), connection.getCallerDisplayNamePresentation());

setConnectionCapabilities(connection.getConnectionCapabilities());
setConnectionProperties(connection.getConnectionProperties());
setVideoProvider(connection.getVideoProvider());
setVideoState(connection.getVideoState());
setRingbackRequested(connection.isRingbackRequested());
setIsVoipAudioMode(connection.getIsVoipAudioMode());
setStatusHints(connection.getStatusHints());
putExtras(SOURCE_CONNECTION_SERVICE, connection.getExtras());

mConferenceableCalls.clear();
for (String id : connection.getConferenceableConnectionIds()) {
mConferenceableCalls.add(idMapper.getCall(id));
}

switch (mCallDirection) {
......
case CALL_DIRECTION_OUTGOING:
for (Listener l : mListeners) {
l.onSuccessfulOutgoingCall(this,
getStateFromConnectionState(connection.getState()));
}
break;
......
}
}

看完上面这段连接建立后的处理,下面继续来看建立连接的流程。
TelephonyConnectionService.java
在onCreateOutgoingConnection()中会有一些列的判断,如号码是否为空、是否需要转换为紧急号码、是否可添加call等,这里就不展开分析了。
public Connection onCreateOutgoingConnection(
PhoneAccountHandle connectionManagerPhoneAccount,
final ConnectionRequest request) {
......
if (isEmergencyNumber && !isRadioOn()) {
......
} else {
......
if(resultConnection instanceof TelephonyConnection) {
placeOutgoingConnection((TelephonyConnection) resultConnection, phone, request);
}
return resultConnection;
}
}

private void placeOutgoingConnection(
TelephonyConnection connection, Phone phone, ConnectionRequest request) {
placeOutgoingConnection(connection, phone, request.getVideoState(), request.getExtras());
}

private void placeOutgoingConnection(
TelephonyConnection connection, Phone phone, int videoState, Bundle extras) {
......
if (phone != null) {
originalConnection = phone.dial(number, null, videoState, extras);
}
......
if (originalConnection == null) {
......
} else {
// 连接建立后,更新连接、通知响应listener连接变化、注册监听一些事件。
// originalConnection是在GsmCdmaCallTracker中建立的。
connection.setOriginalConnection(originalConnection);
}
}

接下来就进入Phone对象中进行处理了。

GsmCdmaPhone.java
dial()中会根据各种条件来判断是拨打CS call还是IMS call,我们这里只讨论CS call。
public Connection dial(String dialString, UUSInfo uusInfo, int videoState, Bundle intentExtras)
throws CallStateException {
......
if (isPhoneTypeGsm()) {
return dialInternal(dialString, null, VideoProfile.STATE_AUDIO_ONLY, intentExtras);
} else {
// For CDMA
......
}
}

dialInternal()中会对补充业务进行处理。对于普通拨号,直接转到GsmCdmaCallTracker进行处理。
protected Connection dialInternal(String dialString, UUSInfo uusInfo, int videoState,
Bundle intentExtras)
throws CallStateException {
......
if (isPhoneTypeGsm()) {
......
if (mmi == null) {
return mCT.dial(newDialString, uusInfo, intentExtras);
} else if (mmi.isTemporaryModeCLIR()) {
..
} else {
......
}
} else {
......
}
}

GsmCdmaCallTracker.java
GsmCdmaCallTracker会做一些拨号前的准备工作,如清除不需要的call、转换号码、创建Connection等。
public Connection dial(String dialString, UUSInfo uusInfo, Bundle intentExtras)
throws CallStateException {
return dial(dialString, CommandsInterface.CLIR_DEFAULT, uusInfo, intentExtras);
}


public synchronized Connection dial(String dialString, int clirMode, UUSInfo uusInfo,
Bundle intentExtras)
throws CallStateException {
// 先清除已断开的call
clearDisconnected();
......
if (mForegroundCall.getState() == GsmCdmaCall.State.ACTIVE) {
// 当前已经有active的call了,这种情况暂不讨论
......
}
......
// 创建连接
mPendingMO = new GsmCdmaConnection(mPhone, checkForTestEmergencyNumber(dialString),
this, mForegroundCall, isEmergencyCall);
mHangupPendingMO = false;

if ( mPendingMO.getAddress() == null || mPendingMO.getAddress().length() == 0
|| mPendingMO.getAddress().indexOf(PhoneNumberUtils.WILD) >= 0) {
......
} else {
// 拨号前先静音
setMute(false);
// 调用RIL的接口向modem发送拨号请求
// 请求返回后会触发EVENT_OPERATION_COMPLETE事件
mCi.dial(mPendingMO.getAddress(), clirMode, uusInfo, obtainCompleteMessage());
}
......
// 更新并通知Call状态变化
updatePhoneState();
mPhone.notifyPreciseCallStateChanged();

return mPendingMO;
}

modem返回请求后,触发EVENT_OPERATION_COMPLETE事件,进而发起查询call状态的请求。
public void handleMessage(Message msg) {
......
case EVENT_OPERATION_COMPLETE:
operationComplete();
break;
......
}

private void operationComplete() {
......
if (mPendingOperations == 0 && mNeedsPoll) {
mLastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT);
mCi.getCurrentCalls(mLastRelevantPoll);
} else if (mPendingOperations < 0) {
......
}
}

至此,App/FW的拨号请求就完成了,接下来就是等待modem上报call状态的变化了。


















 

转载于:https://my.oschina.net/igiantpanda/blog/2222411

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值