上篇博客分析到调用ServiceConnection,这里接着分析
1.ServiceConnection.java类中实现了该远程服务
private final IBinder mBinder = new IConnectionService.Stub() 并重写了其接口,这里我们主要关注
@Override
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();
}
3.这里我们主要追踪其createConnection方法其发送了CREATE_CONNECTION消息,追踪消息处理的地方
private final Handler mHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
...
case MSG_CREATE_CONNECTION: {
SomeArgs args = (SomeArgs) msg.obj;
try {
final PhoneAccountHandle connectionManagerPhoneAccount =
(PhoneAccountHandle) args.arg1;
final String id = (String) args.arg2;
final ConnectionRequest request = (ConnectionRequest) args.arg3;
final boolean isIncoming = args.argi1 == 1;
final boolean isUnknown = args.argi2 == 1;
if (!mAreAccountsInitialized) {
Log.d(this, "Enqueueing pre-init request %s", id);
mPreInitializationConnectionRequests.add(new Runnable() {
@Override
public void run() {
createConnection(
connectionManagerPhoneAccount,
id,
request,
isIncoming,
isUnknown);
}
});
} else {
createConnection(
connectionManagerPhoneAccount,
id,
request,
isIncoming,
isUnknown);
}
} finally {
args.recycle();
}
break;
}
4.使用异步的方式创建了连接,继续分析createConnection
/**
* This can be used by telecom to either create a new outgoing call or attach to an existing
* incoming call. In either case, telecom will cycle through a set of services and call
* createConnection util a connection service cancels the process or completes it successfully.
*/
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);
if (connection == null) {
connection = Connection.createFailedConnection(
new DisconnectCause(DisconnectCause.ERROR));
}
connection.setTelecomCallId(callId);
if (connection.getState() != Connection.STATE_DISCONNECTED) {
addConnection(callId, connection);
}
Uri address = connection.getAddress();
String number = address == null ? "null" : address.getSchemeSpecificPart();
mAdapter.handleCreateConnectionComplete(
callId,
request,
new ParcelableConnection(
request.getAccountHandle(),
connection.getState(),
connection.getConnectionCapabilities(),
connection.getConnectionProperties(),
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();
}
}
5.可以看到其根据connection类型创建对于的coneection,去电走的是onCreateOutgoingConneciton创建,跟进该方法,发现其返回的值为空,应该是其子类进行重载了该方法,跟踪TelephonyConnectionService方法
@Override
public Connection onCreateOutgoingConnection(
PhoneAccountHandle connectionManagerPhoneAccount,
final ConnectionRequest request) {
Log.i(this, "onCreateOutgoingConnection, request: " + request);
...
//判断网络状态,手机号码是否正确,是否是紧急呼叫等,获取phone对象
...
// 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和placeOutgoingConnection
7.那先来看下getTelephonyConnection
private Connection getTelephonyConnection(final ConnectionRequest request, final String number,
boolean isEmergencyNumber, final Uri handle, Phone phone) {
...
//创建失败的一些情况,如phone为空,check 当前网络的状态sim卡设置pin等,紧急状态下拨打非紧急号码等,
...
final TelephonyConnection connection =
createConnectionFor(phone, null, true /* isOutgoing */, request.getAccountHandle(),
request.getTelecomCallId(), request.getAddress(), request.getVideoState());
if (connection == null) {
Log.d(this, "onCreateOutgoingConnection 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());
Log.d(this, "onCreateOutgoingConnection final");
return connection;
}
可以看到这里其实是通过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) {
returnConnection.addTelephonyConnectionListener(mTelephonyConnectionListener);
returnConnection.setVideoPauseSupported(
TelecomAccountRegistry.getInstance(this).isVideoPauseSupported(
phoneAccountHandle));
}
return returnConnection;
}
8.通过getTelephonyConnection方法
根据对于的pnone类型进行创建连接,并添加监听,获取到connection对象。继续分析onCreateOutgoingConnection中的placeOutgoingConnection方法。
private void placeOutgoingConnection(
TelephonyConnection connection, Phone phone, int videoState, Bundle extras,
ConnectionRequest request) {
...
com.android.internal.telephony.Connection originalConnection = null;
try {
if (phone != null) {
if (isAddParticipant) {
...
} else {
...
//调用phone.dial进行呼叫
originalConnection = phone.dial(number, null, request.getVideoState(), bundle);
Log.d(this, "placeOutgoingConnection phone.dial -- originalConnection = " + originalConnection);
9.可以看到其实是通过调用phone.dail进行呼叫,
而phone是具有ril通信能力的,其会调用RIL的dial方法进行处理。具体的可以另外见phone讲解。
这里我们继续分析,android N中cdma和gsm统一由GsmCdmaPhone对象进行处理,我们跟进到此类中的dial方法。
@Override
public Connection dial(String dialString, UUSInfo uusInfo, int videoState, Bundle intentExtras)
throws CallStateException {
...
if ((imsUseEnabled && (!isUt || useImsForUt)) || useImsForEmergency || useImsPrefer) {
try {
if (DBG) logd("Trying IMS PS call");
return imsPhone.dial(dialString, uusInfo, videoState, intentExtras);
} catch (CallStateException e) {
if (DBG) logd("IMS PS call exception " + e +
"imsUseEnabled =" + imsUseEnabled + ", imsPhone =" + imsPhone);
if (!Phone.CS_FALLBACK.equals(e.getMessage())) {
CallStateException ce = new CallStateException(e.getMessage());
ce.setStackTrace(e.getStackTrace());
throw ce;
}
}
}
if (mSST != null && mSST.mSS.getState() == ServiceState.STATE_OUT_OF_SERVICE
&& mSST.mSS.getDataRegState() != ServiceState.STATE_IN_SERVICE && !isEmergency) {
throw new CallStateException("cannot dial in current state");
}
if (DBG) logd("Trying (non-IMS) CS call");
if (isPhoneTypeGsm()) {
return dialInternal(dialString, null, VideoProfile.STATE_AUDIO_ONLY, intentExtras);
} else {
return dialInternal(dialString, null, videoState, intentExtras);
}
}
10.这里我们以GSM为例可以看到CS通话最终根据phone的类型调用不同的dialInternal方法进行呼叫.
protected Connection dialInternal(String dialString, UUSInfo uusInfo, int videoState,
Bundle intentExtras)
throws CallStateException {
String newDialString = PhoneNumberUtils.stripSeparators(dialString);
if (isPhoneTypeGsm()) {
if (handleInCallMmiCommands(newDialString)) {
return null;
}
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) {
}
return null;
}
} else {
return mCT.dial(newDialString);
}
}
11.可以看到其主要通过mCT.dial方法调用进行呼叫,那么这里的mmi和mCT又是什么呢?mmi对号码进行格式化去掉无用数据,在此没有继续深入,有兴趣的朋友可以自行深入。
public GsmCdmaCallTracker mCT;
可以看到其实是通过GsmCdmaCallTracker进行呼叫,这里我们以GSM为例进行进一步分析
/**
* clirMode is one of the CLIR_ constants
*/
public synchronized Connection dial(String dialString, int clirMode, UUSInfo uusInfo,
Bundle intentExtras)
throws CallStateException {
clearDisconnected();
更新一些call的状态
...
if ( mPendingMO.getAddress() == null || mPendingMO.getAddress().length() == 0
|| mPendingMO.getAddress().indexOf(PhoneNumberUtils.WILD) >= 0) {
mPendingMO.mCause = DisconnectCause.INVALID_NUMBER;
pollCallsWhenSafe();
} else {
setMute(false);
mCi.dial(mPendingMO.getAddress(), clirMode, uusInfo, obtainCompleteMessage());
}
if (mNumberConverted) {
mPendingMO.setConverted(origNumber);
mNumberConverted = false;
}
updatePhoneState();
mPhone.notifyPreciseCallStateChanged();
return mPendingMO;
}
可以看到其实是调用mCi的方法进行通信且调用了obtainCompleteMessage方法
先看下obtain方法的调用,用来唤醒getCurrentCalls()
private Message obtainCompleteMessage() {
return obtainCompleteMessage(EVENT_OPERATION_COMPLETE);
}
/**
* Obtain a message to use for signalling "invoke getCurrentCalls() when
* this operation and all other pending operations are complete
*/
private Message obtainCompleteMessage(int what) {
mPendingOperations++;
mLastRelevantPoll = null;
mNeedsPoll = true;
if (DBG_POLL) log("obtainCompleteMessage: pendingOperations=" +
mPendingOperations + ", needsPoll=" + mNeedsPoll);
return obtainMessage(what);
}
private void operationComplete() {
mPendingOperations--;
if (DBG_POLL) log("operationComplete: pendingOperations=" +
mPendingOperations + ", needsPoll=" + mNeedsPoll);
if (mPendingOperations == 0 && mNeedsPoll) {
mLastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT);
mCi.getCurrentCalls(mLastRelevantPoll);
} else if (mPendingOperations < 0) {
Rlog.e(LOG_TAG,"GsmCdmaCallTracker.pendingOperations < 0");
mPendingOperations = 0;
}
}
继续分析mCi.dail
public CommandsInterface mCi;
看下其初始化情况
public GsmCdmaCallTracker (GsmCdmaPhone phone) {
this.mPhone = phone;
mCi = phone.mCi;
...
}
继续追踪GsmCdmaPhone的初始化–>需要查看phone的初始化,可以看到在PhoneFactory中makeDefaultPhone的初始化
public static void makeDefaultPhone(Context context) {
...
//RIL
sCommandsInterfaces = new RIL[numPhones];
sTelephonyNetworkFactories = new TelephonyNetworkFactory[numPhones];
for (int i = 0; i < numPhones; i++) {
// reads the system properties and makes commandsinterface
// Get preferred network type.
networkModes[i] = RILConstants.PREFERRED_NETWORK_MODE;
Rlog.i(LOG_TAG, "Network Mode set to " + Integer.toString(networkModes[i]));
sCommandsInterfaces[i] = new RIL(context, networkModes[i],
cdmaSubscription, i);
}
Rlog.i(LOG_TAG, "Creating SubscriptionController");
telephonyComponentFactory.initSubscriptionController(
context, sCommandsInterfaces);
// Instantiate UiccController so that all other classes can just
// call getInstance()
sUiccController = UiccController.make(context, sCommandsInterfaces);
for (int i = 0; i < numPhones; i++) {
Phone phone = null;
int phoneType = TelephonyManager.getPhoneType(networkModes[i]);
//根据具体的PHONE类型初始化,其中mCi就是RIL
if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
phone = telephonyComponentFactory.makePhone(context,
sCommandsInterfaces[i], sPhoneNotifier, i,
PhoneConstants.PHONE_TYPE_GSM,
telephonyComponentFactory);
} else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
phone = telephonyComponentFactory.makePhone(context,
sCommandsInterfaces[i], sPhoneNotifier, i,
PhoneConstants.PHONE_TYPE_CDMA_LTE,
telephonyComponentFactory);
}
Rlog.i(LOG_TAG, "Creating Phone with type = " + phoneType + " sub = " + i);
sPhones[i] = phone;
}
...
12.可以看到PHONE的创建是根据具体的PHONE类型初始化,其中mCi就是RIL,那么继续看看RIL的dail方法
@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)
} else {
rr.mParcel.writeInt(1)
rr.mParcel.writeInt(uusInfo.getType())
rr.mParcel.writeInt(uusInfo.getDcs())
rr.mParcel.writeByteArray(uusInfo.getUserData())
}
//
if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest))
mMetrics.writeRilDial(mInstanceId, rr.mSerial, clirMode, uusInfo)
//发送消息给底层了,具体可以参见RILJ消息处理机制
send(rr)
}
private void
send(RILRequest rr) {
Message msg;
if (mSocket == null) {
rr.onError(RADIO_NOT_AVAILABLE, null);
rr.release();
return;
}
msg = mSender.obtainMessage(EVENT_SEND, rr);
acquireWakeLock(rr, FOR_WAKELOCK);
msg.sendToTarget();
}
class RILSender extends Handler implements Runnable {
handleMessage(Message msg) {
RILRequest rr = (RILRequest)(msg.obj);
RILRequest req = null;
switch (msg.what) {
case EVENT_SEND:
case EVENT_SEND_ACK:
LocalSocket s;
s = mSocket;
...
s.getOutputStream().write(dataLength);
s.getOutputStream().write(data);
...
break;
...
}
...
...
}
到这里就通过Socket通信下发到底层去了,不过目前在android8.0上已经重写RILJ架构改用一个service进行通信。
以上源码分析流程的时序图如下