三.TelephonyConnectionService.java与RIL.java交互实现通话底层拨号功能
1).上面已经讲到创建通话连接的过程,通话连接创建完毕之后通话流程就会流转到通话拨号过程,事实上这两步是异步的,我们可以看一下,这个动作是在ConnectionService.java((packages/services/telecomm)中的createConnection方法中进行的:
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));}
if(connection.getState() != Connection.STATE_DISCONNECTED) {
addConnection(callId, connection);}
Uri address =connection.getAddress();
String number= address == null ? "null" : address.getSchemeSpecificPart();
Log.v(this,"createConnection, number: %s, state: %s, capabilities: %s",
Connection.toLogSafePhoneNumber(number),
Connection.stateToString(connection.getState()),
Connection.capabilitiesToString(connection.getConnectionCapabilities()));
Log.d(this,"createConnection, calling handleCreateConnectionSuccessful %s",callId);
mAdapter.handleCreateConnectionComplete(
callId,
request,
new ParcelableConnection(
request.getAccountHandle(),
connection.getState(),
connection.getConnectionCapabilities(),
connection.getAddress(),
connection.getAddressPresentation(),
connection.getCallerDisplayName(),
connection.getCallerDisplayNamePresentation(),
connection.getVideoProvider() == null?
null :connection.getVideoProvider().getInterface(),
connection.getVideoState(),
connection.isRingbackRequested(),
connection.getAudioModeIsVoip(),
connection.getStatusHints(),
connection.getDisconnectCause(),
createIdList(connection.getConferenceables())));
我们看到上面首先调用到了onCreateOutgoingConnection(callManagerAccount,request)去创建连接并且做拨号动作,同时在最后调用mAdapter.handleCreateConnectionComplete,事实上就是调用ConnectionServiceWrapper.java(packages/services/telecomm)中的内部类的 handleCreateConnectionComplete方法,这个方法我们之前讲过很多遍,即通知更改Call的状态继而去显示通话界面,好了,清楚了这两步之后我们再去关注这个创建连接并且真正拨号的过程;
2).首先查看onCreateOutgoingConnection方法,这个方法最终会调用到placeOutgoingConnection方法,看如下代码:
final Phone phone =getPhoneForAccount(request.getAccountHandle(), isEmergencyNumber);
placeOutgoingConnection(connection, phone,request);
看上面的调用过程中间省略了一些代码,都是一些判断的逻辑,在创建了phone对象后,会将此对象作为一个参数传给placeOutgoingConnection方法,这个phone是Phone类的实例吗,我们看一下 getPhoneForAccount方法:
if (Objects.equals(mExpectedComponentName,accountHandle.getComponentName())) {
if (accountHandle.getId() != null) {
try {
int phoneId =SubscriptionController.getInstance().getPhoneId(
Integer.parseInt(accountHandle.getId()));
return PhoneFactory.getPhone(phoneId);
} catch (NumberFormatException e) {
Log.w(this, "Could not get subId from account:" + accountHandle.getId());
}
}}
看如上逻辑,最后会调用PhoneFactory.getPhone(phoneId)方法去拿到这个实例,我们继续追踪到 PhoneFactory.java(frameworks/opt/telephony)中,查看getPhone方法:
synchronized (sLockProxyPhones) {
if (!sMadeDefaults) {
throw new IllegalStateException("Default phones haven't beenmade yet!");
// CAF_MSIM FIXME need to introduce default phone id ?
} else if (phoneId == SubscriptionManager.DEFAULT_PHONE_INDEX) {
dbgInfo = "phoneId == DEFAULT_PHONE_ID returnsProxyPhone";
phone = sProxyPhone;
} else {
dbgInfo = "phoneId != DEFAULT_PHONE_ID returnsProxyPhones[phoneId]";
phone = (((phoneId >= 0)
&& (phoneId < TelephonyManager.getDefault().getPhoneCount()))
? sProxyPhones[phoneId] : null);
}
Rlog.d(LOG_TAG, "getPhone:- " + dbgInfo + " phoneId=" +phoneId + " phone=" + phone);
return phone;}
看,这里有一个同步块来保证这个phone实例被调用时不会发生死锁现象,我们看到里面最终会将 sProxyPhone赋值给phone,查看 sProxyPhone定义:
static private PhoneProxy sProxyPhone= null;
我们可以看到这个 sProxyPhone是 PhoneProxy类的实例,我们继续搜索看看在什么地方给其赋值了,定位到makeDefaultPhone方法:
int numPhones =TelephonyManager.getDefault().getPhoneCount();
int[] networkModes = new int[numPhones];
sProxyPhones = new PhoneProxy[numPhones];
sCommandsInterfaces = new RIL[numPhones];
for (int i = 0; i < numPhones; i++) {
//reads the system properties and makescommandsinterface
// 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");
SubscriptionController.init(context, sCommandsInterfaces);
// Instantiate UiccController so that all other classes can just
// call getInstance()
mUiccController = UiccController.make(context,sCommandsInterfaces);
mVTManagerProxy = mVTManagerProxy.init(context);
for (int i = 0; i < numPhones; i++) {
Phone phone = null;
int phoneType =TelephonyManager.getPhoneType(networkModes[i]);
if(TelephonyManager.getVolteEnabled()){
phone = new VoltePhone(context,
sCommandsInterfaces[i], sPhoneNotifier, i);
mVTManagerProxy.registerForMessages((GSMPhone)phone);
} else if (phoneType == PhoneConstants.PHONE_TYPE_GSM){
phone = new GSMPhone(context,
sCommandsInterfaces[i], sPhoneNotifier, i);
mVTManagerProxy.registerForMessages((GSMPhone)phone);
} else if (phoneType ==PhoneConstants.PHONE_TYPE_CDMA) {
phone = new CDMALTEPhone(context,
sCommandsInterfaces[i], sPhoneNotifier, i);
}
Rlog.i(LOG_TAG, "Creating Phone with type =" + phoneType + " sub = " + i);
sProxyPhones[i] = new PhoneProxy(phone);
}
mProxyController =(ProxyController)ProxyController.getInstance(context, sProxyPhones,
mUiccController,sCommandsInterfaces);
sProxyPhone = sProxyPhones[0];
sCommandsInterface = sCommandsInterfaces[0];
我们先不去关心makeDefaultPhone方法是在什么地方被调用的,我们先看上面的逻辑,首先:
sProxyPhones = new PhoneProxy[numPhones];
创建了一个sProxyPhones对象数组,接着在下面的for循环中逐个根据类型去创建不同的phone对象,然后将所有的创建好的phone对象保存在sProxyPhones数组中,我们这里之需要看这一行即可:
phone = new GSMPhone(context,
sCommandsInterfaces[i], sPhoneNotifier, i);
到这里,相信大家已经很明白了,我们之前的phone并不是Phone类的直接对象,而是其子类 GSMPhone的对象,并且在最后将这个phone加入到 sProxyPhones数组中去,我们看到最后:
sProxyPhone = sProxyPhones[0];
还是将此数组的第一个元素赋值给了 sProxyPhone, 所以更加确定了, getPhone方法最后返回的就是这个实例,即GSMPhone.java(frameworks/opt/)类的实例,这里其实是GSMPhone.java类,到这里我们明白了这个Phone的实例其实是GSMPhone类型的对象,那么接下来的调用我们继续分析。