Telephony基础之VoiceCall业务(MO流程向下拨号)
MO流程之向下拨号时序图
接前面的CallIntentProcessor.processOutgoingCallIntent():
static void processOutgoingCallIntent(
Context context,
CallsManager callsManager,
Intent intent) {
...
// Send to CallsManager to ensure the InCallUI gets kicked off before the broadcast returns
Call call = callsManager
.startOutgoingCall(handle, phoneAccountHandle, clientExtras, initiatingUser);
if (call != null) {
// Asynchronous calls should not usually be made inside a BroadcastReceiver because once
// onReceive is complete, the BroadcastReceiver's process runs the risk of getting
// killed if memory is scarce. However, this is OK here because the entire Telecom
// process will be running throughout the duration of the phone call and should never
// be killed.
NewOutgoingCallIntentBroadcaster broadcaster = new NewOutgoingCallIntentBroadcaster(
context, callsManager, call, intent, callsManager.getPhoneNumberUtilsAdapter(),
isPrivilegedDialer);
final int result = broadcaster.processIntent();
final boolean success = result == DisconnectCause.NOT_DISCONNECTED;
if (!success && call != null) {
callsManager.clearPendingMOEmergencyCall();
disconnectCallAndShowErrorDialog(context, call, result);
}
}
}
进入NewOutgoingCallIntentBroadcaster.processIntent():
public int processIntent() {
....
Log.i(this, "Sending NewOutgoingCallBroadcast for %s to %s", mCall, targetUser);
if (isSkipSchemaParsing) {
broadcastIntent(intent, handle.toString(), !callImmediately, targetUser);
} else {
broadcastIntent(intent, number, !callImmediately, targetUser);
}
return DisconnectCause.NOT_DISCONNECTED;
}
进入broadcastIntent():
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
}
进入NewOutgoingCallBroadcastIntentReceiver.onReceive():
@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.placeOutgoingCall():
public void placeOutgoingCall(Call call, Uri handle, GatewayInfo gatewayInfo,
...
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.
call.startCreateConnection(mPhoneAccountRegistrar);
}
}
...
}
进入Call.startCreateConnection():
void 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();
}
进入CreateConnectionProcessor.process():
public void process() {
Log.v(this, "process");
clearTimeout();
mAttemptRecords = new ArrayList<>();
if (mCall.getTargetPhoneAccount() != null) {
mAttemptRecords.add(new CallAttemptRecord(
mCall.getTargetPhoneAccount(), mCall.getTargetPhoneAccount()));
}
adjustAttemptsForConnectionManager();
adjustAttemptsForEmergency(mCall.getTargetPhoneAccount());
mAttemptRecordIterator = mAttemptRecords.iterator();
attemptNextPhoneAccount();
}
进入attemptNextPhoneAccount():
private void attemptNextPhoneAccount() {
...
if (mCallResponse != null && attempt != null) {
Log.i(this, "Trying attempt %s", attempt);
PhoneAccountHandle phoneAccount = attempt.connectionManagerPhoneAccount;
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);
mService.createConnection(mCall, this);
}
}
...
}
进入ConnectionServiceWrapper.createConnection():
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));
}
};
mBinder.bind(callback, call);
}
进入ServiceBinder.Binder2. bind():
void bind(BindCallback callback, Call call) {
...
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;
}
}
}
通过mContext.bindServiceAsUser()绑定TelephonyConnectionService成功后,回调ServiceBinder.ServiceBinderConnection.onServiceConnected():
@Override
public void onServiceConnected(ComponentName componentName, IBinder binder) {
try {
Log.startSession("SBC.oSC");
synchronized (mLock) {
Log.i(this, "Service bound %s", componentName);
....
mServiceConnection = this;
setBinder(binder);
handleSuccessfulConnection();
}
} finally {
Log.endSession();
}
}
先通过setBinder()向ConnectionServiceWrapper设置mServiceInterface,向TelephonyConnectionService设置mAdapter.
之后通过ServiceBinder.handleSuccessfulConnection()回调CallBack.
进入ServiceBinder.handleSuccessfulConnection():
private void handleSuccessfulConnection() {
for (BindCallback callback : mCallbacks) {
callback.onSuccess();
}
mCallbacks.clear();
}
这里的callback是之前ConnectionServiceWrapper.createConnection()传入的.
进入BindCallback.onSuccess():
public void onSuccess() {
...
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()));
}
}
通过mServiceInterface.createConnection()调用服务端的service创建Connection.
这里的mServiceInterface是之前绑定成功后返回的ConnectionService中的mBinder对象.
进入ConnectionService.IBinder.createConnection():
public void createConnection(
PhoneAccountHandle connectionManagerPhoneAccount,
String id,
ConnectionRequest request,
boolean isIncoming,
boolean isUnknown) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = connectionManagerPhoneAccount;
args.arg2 = id;
args.arg3 = request;
args.argi1 = isIncoming ? 1 : 0;
args.argi2 = isUnknown ? 1 : 0;
mHandler.obtainMessage(MSG_CREATE_CONNECTION, args).sendToTarget();
}
进入ConnectionService.Handler.handleMessage():
case MSG_CREATE_CONNECTION: {
...
} else {
createConnection(
connectionManagerPhoneAccount,
id,
request,
isIncoming,
isUnknown);
}
进入ConnectionService.createConnection():
private void createConnection(
final PhoneAccountHandle callManagerAccount,
final String callId,
final ConnectionRequest request,
boolean isIncoming,
boolean isUnknown) {
Log.d(this, "createConnection, callManagerAccount: %s, callId: %s, request: %s, " +
"isIncoming: %b, isUnknown: %b", callManagerAccount, callId, request,
isIncoming,
isUnknown);
Connection connection = isUnknown ? onCreateUnknownConnection(callManagerAccount, request)
: isIncoming ? onCreateIncomingConnection(callManagerAccount, request)
: onCreateOutgoingConnection(callManagerAccount, request);
Log.d(this, "createConnection, connection: %s", connection);
...
mAdapter.handleCreateConnectionComplete(
callId,
request,
new ParcelableConnection(
request.getAccountHandle(),
connection.getState(),
connection.getConnectionCapabilities(),
connection.getConnectionProperties(),
connection.getSupportedAudioRoutes(),
connection.getAddress(),
connection.getAddressPresentation(),
connection.getCallerDisplayName(),
connection.getCallerDisplayNamePresentation(),
connection.getVideoProvider() == null ?
null : connection.getVideoProvider().getInterface(),
connection.getVideoState(),
connection.isRingbackRequested(),
connection.getAudioModeIsVoip(),
connection.getConnectTimeMillis(),
connection.getStatusHints(),
connection.getDisconnectCause(),
createIdList(connection.getConferenceables()),
connection.getExtras()));
if (isUnknown) {
triggerConferenceRecalculate();
}
}
这里比较重要,通过onCreateOutgoingConnection()创建MO的connection,成功返回后在后面通过mAdapter.handleCreateConnectionComplete()通知ConnectionServiceWrapper.
这里先来看onCreateOutgoingConnection(),因为TelephonyConnectionService extends ConnectionService,所以这几个方法会在TelephonyConnectionService中重写,所以在
分析MO与MT的一些问题时,这里可以作为问题的一个切分点.
进入TelephonyConnectionService.onCreateOutgoingConnection():
@Override
public Connection onCreateOutgoingConnection(
PhoneAccountHandle connectionManagerPhoneAccount,
final ConnectionRequest request) {
Log.i(this, "onCreateOutgoingConnection, request: " + request);
...
} else {
if (!canAddCall() && !isEmergencyNumber) {
Log.d(this, "onCreateOutgoingConnection, cannot add call .");
return Connection.createFailedConnection(
new DisconnectCause(DisconnectCause.ERROR,
getApplicationContext().getText(
R.string.incall_error_cannot_add_call),
getApplicationContext().getText(
R.string.incall_error_cannot_add_call),
"Add call restricted due to ongoing video call"));
}
// Get the right phone object from the account data passed in.
final Phone phone = getPhoneForAccount(request.getAccountHandle(), isEmergencyNumber);
Connection resultConnection = getTelephonyConnection(request, numberToDial,
isEmergencyNumber, handle, phone);
// If there was a failure, the resulting connection will not be a TelephonyConnection,
// so don't place the call!
if(resultConnection instanceof TelephonyConnection) {
placeOutgoingConnection((TelephonyConnection) resultConnection, phone, request);
}
return resultConnection;
}
这里先通过getTelephonyConnection()获得resultConnection,然后通过placeOutgoingConnection()向RIL层发起拨号.
先进入TelephonyConnectionService.getTelephonyConnection():
private Connection getTelephonyConnection(final ConnectionRequest request, final String number,
boolean isEmergencyNumber, final Uri handle, Phone phone) {
...
final TelephonyConnection connection =
createConnectionFor(phone, null, true /* isOutgoing */, request.getAccountHandle(),
request.getTelecomCallId(), request.getAddress(), request.getVideoState());
if (connection == null) {
return Connection.createFailedConnection(
DisconnectCauseUtil.toTelecomDisconnectCause(
android.telephony.DisconnectCause.OUTGOING_FAILURE,
"Invalid phone type"));
}
connection.setAddress(handle, PhoneConstants.PRESENTATION_ALLOWED);
connection.setInitializing();
connection.setVideoState(request.getVideoState());
return connection;
}
注意:这里创建的的TelephonyConnection是GsmConnection/CdmaConnection,是Telephony Service connection
而其参数originalConnection是com.android.internal.telephony.GsmCdmaConnection.
进入TelephonyConnectionService.createConnectionFor():
private TelephonyConnection createConnectionFor(
Phone phone,
com.android.internal.telephony.Connection originalConnection,
boolean isOutgoing,
PhoneAccountHandle phoneAccountHandle,
String telecomCallId,
Uri address,
int videoState) {
TelephonyConnection returnConnection = null;
int phoneType = phone.getPhoneType();
if (phoneType == TelephonyManager.PHONE_TYPE_GSM) {
returnConnection = new GsmConnection(originalConnection, telecomCallId);
} else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) {
boolean allowsMute = allowsMute(phone);
returnConnection = new CdmaConnection(originalConnection, mEmergencyTonePlayer,
allowsMute, isOutgoing, telecomCallId);
}
if (returnConnection != null) {
// Listen to Telephony specific callbacks from the connection
returnConnection.addTelephonyConnectionListener(mTelephonyConnectionListener);
returnConnection.setVideoPauseSupported(
TelecomAccountRegistry.getInstance(this).isVideoPauseSupported(
phoneAccountHandle));
}
return returnConnection;
}
返回TelephonyConnectionService.onCreateOutgoingConnection(),
进入TelephonyConnectionService.placeOutgoingConnection():
private void placeOutgoingConnection(
TelephonyConnection connection, Phone phone, int videoState, Bundle extras,
ConnectionRequest request) {
...
Log.d(this, "placeOutgoingConnection isAddParticipant = " + isAddParticipant);
com.android.internal.telephony.Connection originalConnection = null;
try {
if (phone != null) {
if (isAddParticipant) {
phone.addParticipant(number);
return;
} else {
originalConnection = phone.dial(number, null, request.getVideoState(), bundle);
}
}
}
进入GsmCdmaPhone.dial():
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 {
return dialInternal(dialString, null, videoState, intentExtras);
}
}
进入GsmCdmaPhone.dialInternal():
protected Connection dialInternal(String dialString, UUSInfo uusInfo, int videoState,
Bundle intentExtras)
throws CallStateException {
...
if (isPhoneTypeGsm()) {
// handle in-call MMI first if applicable
if (handleInCallMmiCommands(newDialString)) {
return null;
}
// Only look at the Network portion for mmi
String networkPortion = PhoneNumberUtils.extractNetworkPortionAlt(newDialString);
GsmMmiCode mmi =
GsmMmiCode.newFromDialString(networkPortion, this, mUiccApplication.get());
if (DBG) logd("dialing w/ mmi '" + mmi + "'...");
if (mmi == null) {
return mCT.dial(newDialString, uusInfo, intentExtras);
} else if (mmi.isTemporaryModeCLIR()) {
return mCT.dial(mmi.mDialingNumber, mmi.getCLIRMode(), uusInfo, intentExtras);
} else {
mPendingMMIs.add(mmi);
mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
try {
mmi.processCode();
} catch (CallStateException e) {
//do nothing
}
// FIXME should this return null or something else?
return null;
}
} else {
return mCT.dial(newDialString);
}
进入GsmCdmaCallTracker.dial():
public synchronized Connection dial(String dialString, int clirMode, UUSInfo uusInfo,
Bundle intentExtras)
throws CallStateException {
...
if ( mPendingMO.getAddress() == null || mPendingMO.getAddress().length() == 0
|| mPendingMO.getAddress().indexOf(PhoneNumberUtils.WILD) >= 0) {
// Phone number is invalid
mPendingMO.mCause = DisconnectCause.INVALID_NUMBER;
// handlePollCalls() will notice this call not present
// and will mark it as dropped.
pollCallsWhenSafe();
} else {
// Always unmute when initiating a new call
setMute(false);
mCi.dial(mPendingMO.getAddress(), clirMode, uusInfo, obtainCompleteMessage());
}
}
进入RIL.dial():
@Override
public void
dial(String address, int clirMode, UUSInfo uusInfo, Message result) {
RILRequest rr = RILRequest.obtain(RIL_REQUEST_DIAL, result);
rr.mParcel.writeString(address);
rr.mParcel.writeInt(clirMode);
if (uusInfo == null) {
rr.mParcel.writeInt(0); // UUS information is absent
} else {
rr.mParcel.writeInt(1); // UUS information is present
rr.mParcel.writeInt(uusInfo.getType());
rr.mParcel.writeInt(uusInfo.getDcs());
rr.mParcel.writeByteArray(uusInfo.getUserData());
}
if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
send(rr);
}
至此,MO的AP层拨号完成.
之后返回到前面说的ConnectionService.createConnection(),通过mAdapter.handleCreateConnectionComplete()逐层上报拨号情况.