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