第三章:通话连接的作用以及建立过程之三TelephonyConnectionService.java与RIL.java交互实现通话底层拨号功能

三.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类型的对象,那么接下来的调用我们继续分析。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值