上篇博客分析到调用broadcastIntent,这里接着分析
1.接着查看NewOutgoingCallIntentBroadcaster.java文件中的broadcastIntent方法:
private void broadcastIntent(
Intent originalCallIntent,
String number,
boolean receiverRequired,
UserHandle targetUser) {
//要发送的广播
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);
Log.p(TAG, "broadcastIntent(): EXTRA_PHONE_NUMBER " + number);
checkAndCopyProviderExtras(originalCallIntent, broadcastIntent);
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
}
2.这里看到发送一个Intent.ACTION_NEW_OUTGOING_CALL广播,对于非紧急拨号,才会生成一个
NewOutgoingCallBroadcastIntentReceive 实例来接收该广播,我们跟进onReceive方法
public class NewOutgoingCallBroadcastIntentReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
try {
...
GatewayInfo gatewayInfo = getGateWayInfoFromIntent(intent, resultHandleUri);
mCall.setNewOutgoingCallIntentBroadcastIsDone();
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));
}
}
}
}
3.NewOutgoingCallBroadcastIntentReceiver内部做了一些处理后最后还是调用到CallsManager的placeOutgoingCall方法,所以该方法是去电的关键方法继续看callManager.placeOutgoingCall方法
public void placeOutgoingCall(Call call, Uri handle, GatewayInfo gatewayInfo,
boolean speakerphoneOn, int videoState) {
...
call.setHandle(uriHandle);
call.setGatewayInfo(gatewayInfo);
final boolean useSpeakerWhenDocked = mContext.getResources().getBoolean(
R.bool.use_speaker_when_docked);
final boolean useSpeakerForDock = isSpeakerphoneEnabledForDock();
final boolean useSpeakerForVideoCall = isSpeakerphoneAutoEnabledForVideoCalls(videoState);
// Auto-enable speakerphone if the originating intent specified to do so, if the call
// is a video call, of if using speaker when docked
call.setStartWithSpeakerphoneOn(speakerphoneOn || useSpeakerForVideoCall
|| (useSpeakerWhenDocked && useSpeakerForDock));
call.setVideoState(videoState);
if (call.isEmergencyCall()) {
new AsyncEmergencyContactNotifier(mContext).execute();
}
final boolean requireCallCapableAccountByHandle = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_requireCallCapableAccountForHandle);
if (call.getTargetPhoneAccount() != null || call.isEmergencyCall()) {
if (!call.isEmergencyCall()) {
updateLchStatus(call.getTargetPhoneAccount().getId());
}
//Block to initiate Emregency call now as the current active call
//is not yet disconnected.
if (mPendingMOEmerCall == null) {
// If the account has been set, proceed to place the outgoing call.
// Otherwise the connection will be initiated when the account is set by the user.
// +++ Delay 1500 ms to speed up launch inCallUI
int time = android.os.SystemProperties.getInt("persist.asus.tellril", 0);
Log.d(TAG, "placeOutgoingCall(): persist.asus.tellril time = " + time);
if (time == 0 ||call.isEmergencyCall()) {
Log.d(TAG, "placeOutgoingCall(): no delay to startCreateConnection");
//创建连接
call.startCreateConnection(mPhoneAccountRegistrar);
} else {
new android.os.CountDownTimer(time, time) {
@Override
public void onTick(long millisUntilFinished) {
}
@Override
public void onFinish() {
Log.d(TAG, "placeOutgoingCall(): delay time to startCreateConnection");
call.startCreateConnection(mPhoneAccountRegistrar);
}
}.start();
}
}
// --- Delay 1500 ms to speed up launch inCallUI
} else if (mPhoneAccountRegistrar.getCallCapablePhoneAccounts(
requireCallCapableAccountByHandle ? call.getHandle().getScheme() : null, false,
call.getInitiatingUser()).isEmpty()) {
// If there are no call capable accounts, disconnect the call.
markCallAsDisconnected(call, new DisconnectCause(DisconnectCause.CANCELED,
"No registered PhoneAccounts"));
markCallAsRemoved(call);
}
}
4.如果是Video Call或者是紧急呼叫的话会做一些额外操作,如果条件满足的话会调用到startCreateConnection建立连接
void startCreateConnection(PhoneAccountRegistrar phoneAccountRegistrar) {
Log.d(TAG, "startCreateConnection(): phoneAccountRegistrar " + phoneAccountRegistrar);
if (mCreateConnectionProcessor != null) {
Log.w(this, "mCreateConnectionProcessor in startCreateConnection is not null. This is" +
" due to a race between NewOutgoingCallIntentBroadcaster and " +
"phoneAccountSelected, but is harmlessly resolved by ignoring the second " +
"invocation.");
return;
}
mCreateConnectionProcessor = new CreateConnectionProcessor(this, mRepository, this,
phoneAccountRegistrar, mContext);
mCreateConnectionProcessor.process();
}
5.新建了一个CreateConnectionProcessor对象,处理连接请求
@VisibleForTesting
public void process() {
Log.v(this, "process");
clearTimeout();
mAttemptRecords = new ArrayList<>();
if (mCall.getTargetPhoneAccount() != null) {
Log.d(this, "process mCall.getTargetPhoneAccount() = " + mCall.getTargetPhoneAccount());
mAttemptRecords.add(new CallAttemptRecord(
mCall.getTargetPhoneAccount(), mCall.getTargetPhoneAccount()));
} else {
Log.d(this, "process mCall.getTargetPhoneAccount() is null");
}
adjustAttemptsForConnectionManager();
adjustAttemptsForEmergency(mCall.getTargetPhoneAccount());
mAttemptRecordIterator = mAttemptRecords.iterator();
attemptNextPhoneAccount();
}
6.进入attemptNextPhoneAccount方法
private void attemptNextPhoneAccount() {
Log.v(this, "attemptNextPhoneAccount");
CallAttemptRecord attempt = null;
if (mAttemptRecordIterator.hasNext()) {
attempt = mAttemptRecordIterator.next();
if (!mPhoneAccountRegistrar.phoneAccountRequiresBindPermission(
attempt.connectionManagerPhoneAccount)) {
Log.w(this,
"Connection mgr does not have BIND_TELECOM_CONNECTION_SERVICE for "
+ "attempt: %s", attempt);
attemptNextPhoneAccount();
return;
}
// If the target PhoneAccount differs from the ConnectionManager phone acount, ensure it
// also requires the BIND_TELECOM_CONNECTION_SERVICE permission.
if (!attempt.connectionManagerPhoneAccount.equals(attempt.targetPhoneAccount) &&
!mPhoneAccountRegistrar.phoneAccountRequiresBindPermission(
attempt.targetPhoneAccount)) {
Log.w(this,
"Target PhoneAccount 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 phoneAccount = attempt.connectionManagerPhoneAccount;
// 获取ConnectionServiceWrapper对象
mService = mRepository.getService(phoneAccount.getComponentName(),
phoneAccount.getUserHandle());
if (mService == null) {
Log.i(this, "Found no connection service for attempt %s", attempt);
attemptNextPhoneAccount();
} else {
mConnectionAttempt++;
mCall.setConnectionManagerPhoneAccount(attempt.connectionManagerPhoneAccount);
mCall.setTargetPhoneAccount(attempt.targetPhoneAccount);
mCall.setConnectionService(mService);
setTimeoutIfNeeded(mService, attempt);
// 已成功获取ConnectionServiceWrapper对象,创建连接
mService.createConnection(mCall, this);
}
} else {
Log.v(this, "attemptNextPhoneAccount, no more accounts, failing");
DisconnectCause disconnectCause = mLastErrorDisconnectCause != null ?
mLastErrorDisconnectCause : new DisconnectCause(DisconnectCause.ERROR);
notifyCallConnectionFailure(disconnectCause);
}
}
这里主要的两步操作是获取ConnectionServiceWrapper对象,并调用createConnection方法创建连接。那么我们继续跟进 ConnectionServiceWrapper。
/**
* Wrapper for {@link IConnectionService}s, handles binding to {@link IConnectionService} and keeps
* track of when the object can safely be unbound. Other classes should not use
* {@link IConnectionService} directly and instead should use this class to invoke methods of
* {@link IConnectionService}.
*/
@VisibleForTesting
public class ConnectionServiceWrapper extends ServiceBinder {
实际上就是一个包装了绑定远程服务的代理类,看看它的构造方法
ConnectionServiceWrapper(
ComponentName componentName,
ConnectionServiceRepository connectionServiceRepository,
PhoneAccountRegistrar phoneAccountRegistrar,
CallsManager callsManager,
Context context,
TelecomSystem.SyncRoot lock,
UserHandle userHandle) {
super(ConnectionService.SERVICE_INTERFACE, componentName, context, lock, userHandle);
mConnectionServiceRepository = connectionServiceRepository;
phoneAccountRegistrar.addListener(new PhoneAccountRegistrar.Listener() {
// TODO -- Upon changes to PhoneAccountRegistrar, need to re-wire connections
// To do this, we must proxy remote ConnectionService objects
});
mPhoneAccountRegistrar = phoneAccountRegistrar;
mCallsManager = callsManager;
mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
}
这里的ConnectionService.SERVICE_INTERFACE就是”android.telecom.ConnectionService”也就是它所绑定的远程服务的action,获取该对象后调用createConnection方法
7.继续跟进createConnection方法
/**
* Creates a new connection for a new outgoing call or to attach to an existing incoming call.
*/
@VisibleForTesting
public void createConnection(final Call call, final CreateConnectionResponse response) {
Log.d(this, "createConnection(%s) via %s.", call, getComponentName());
BindCallback callback = new BindCallback() {
@Override
public void onSuccess() {//最终创建成功后会回到这里的回调方法
String callId = mCallIdMapper.getCallId(call);
mPendingResponses.put(callId, response);
GatewayInfo gatewayInfo = call.getGatewayInfo();
Bundle extras = call.getIntentExtras();
if (gatewayInfo != null && gatewayInfo.getGatewayProviderPackageName() != null &&
gatewayInfo.getOriginalAddress() != null) {
extras = (Bundle) extras.clone();
extras.putString(
TelecomManager.GATEWAY_PROVIDER_PACKAGE,
gatewayInfo.getGatewayProviderPackageName());
extras.putParcelable(
TelecomManager.GATEWAY_ORIGINAL_ADDRESS,
gatewayInfo.getOriginalAddress());
}
Log.event(call, Log.Events.START_CONNECTION, Log.piiHandle(call.getHandle()));
try {
mServiceInterface.createConnection(
call.getConnectionManagerPhoneAccount(),
callId,
new ConnectionRequest(
call.getTargetPhoneAccount(),
call.getHandle(),
extras,
call.getVideoState(),
callId),
call.shouldAttachToExistingConnection(),
call.isUnknown());
} catch (RemoteException e) {
Log.e(this, e, "Failure to createConnection -- %s", getComponentName());
mPendingResponses.remove(callId).handleCreateConnectionFailure(
new DisconnectCause(DisconnectCause.ERROR, e.toString()));
}
}
@Override
public void onFailure() {
Log.e(this, new Exception(), "Failure to call %s", getComponentName());
response.handleCreateConnectionFailure(new DisconnectCause(DisconnectCause.ERROR));
}
};
//将callback和call传入
mBinder.bind(callback, call);
}
8.我们看到其创建了BindCallback ,然后使用mBinder调用bind方法。这里的mBinder对象是ConnectionServiceWrapper的父类ServiceBinder里的一个内部类,继续查看其bind调用。
void bind(BindCallback callback, Call call) {
Log.d(ServiceBinder.this, "bind()");
// Reset any abort request if we're asked to bind again.
clearAbort();
if (!mCallbacks.isEmpty()) {
// Binding already in progress, append to the list of callbacks and bail out.
mCallbacks.add(callback);
return;
}
mCallbacks.add(callback);
if (mServiceConnection == null) {
Intent serviceIntent = new Intent(mServiceAction).setComponent(mComponentName);
//创建ServiceConnection服务
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();
}
}
9.这里我们看到主要是创建一个服务,然后调用mContext.bindService进行绑定服务,
10.跟进ServiceBinderConnection继续分析onServiceConnected。
private final class ServiceBinderConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName componentName, IBinder binder) {
try {
Log.startSession("SBC.oSC");
synchronized (mLock) {
Log.i(this, "Service bound %s", componentName);
Log.event(mCall, Log.Events.CS_BOUND, componentName);
mCall = null;
// Unbind request was queued so unbind immediately.
if (mIsBindingAborted) {
clearAbort();
logServiceDisconnected("onServiceConnected");
mContext.unbindService(this);
handleFailedConnection();
return;
}
mServiceConnection = this;
//
setBinder(binder);
handleSuccessfulConnection();
}
} finally {
Log.endSession();
}
}
11.看到设置了binder,设置成功后调用handleSucessfulCOnnection方法,继续根据setBinder看看。
private void setBinder(IBinder binder) {
if (mBinder != binder) {
if (binder == null) {
removeServiceInterface();
mBinder = null;
for (Listener l : mListeners) {
l.onUnbind(this);
}
} else {
mBinder = binder;
setServiceInterface(binder);
}
}
}
12.这里我们看到setServiceInterface只是个接口,回到其子类ConnectionServiceWrapper.java中查看具体实现
/** {@inheritDoc} */
@Override
protected void setServiceInterface(IBinder binder) {
Log.d(TAG, "setServiceInterface(): binder " + binder);
mServiceInterface = IConnectionService.Stub.asInterface(binder);
Log.v(this, "Adding Connection Service Adapter.");
addConnectionServiceAdapter(mAdapter);
}
13.看到其获取远程IConnectionService服务的aidl接口,然后我们继续回到10跟踪handleSuccessfulConnection方法
private void handleSuccessfulConnection() {
for (BindCallback callback : mCallbacks) {
callback.onSuccess();
}
mCallbacks.clear();
}
14.我们看到其调用了callback.onSuccess(),而这个callback其实是我们之前传参带入后进行初始化的,就回到7的onSucess方法中继续调用。
总结7-14的分析, mBinder.bind(callback, call)该方法调用时会创建一个连接,封装了绑定远程服务的一些操作,若当前还未绑定服务,则直接调用bindService获取远程服务的aidl接口,成功获取到aidl接口后将其赋值给mServiceInterface,当绑定完成后会调用handleSuccessFulConnection方法,其回调了CallBack的onSuccess方法。至此就完成了服务的创建及连接
接下来的流程就到了远程服务的createConnection实现了。
根据以上源码分析的流程整理的时序图如下,如果不清楚可以另存为到本地查看。
结合上一章的分析的第五步进入telecomManager到这章的末尾分析来看
其实在telecomManager中获取(ITelecomService.aidl)TelecomService后一路调用,期间有进行一些过滤等操作,最终其实主要做的就是是通过AIDL的调用去获取底层的服务以创建一个连接通道。