基于Android6.0的RIL框架层模块分析
2016-06-22 10:45
639 查看
本文与另外一篇分析RIL底层模块的文章是姐妹篇: 基于Android6.0的RIL底层模块分析
根据手机网络制式的不同,通常系统中会扩展Phone.java这个类,扩展成GSMPhone和CDMAPhone。这个类主要是抽象整个手机来处理通信过程中与其他模块的交互。我们以GSMPhone为例,分析来电流程如何从底层传递到上层。该分析主要基于代码,所以会比较啰嗦。
以GSMPhone为例,在PhoneFactory类中有实例化该类的方法:
这个phone的mCi其实使用sCommandInterfaces第phoneId个元素进行初始化。这个数组是为了支持多卡而设置。
sCommandInterfaces的初始化是:
所以可以知道其实mCi的真实类型就是RIL类。
GSMPhone会构造一个GsmCallTracker,而在GsmCallTracker中就会在构造函数中调用:
其实就是用GsmCallTracker来监听mCi上的电话状态改变EVENT_CALL_STATE_CHANGE啊。注意这个mCi是CommandInterfaces类型(当然实际是RIL类型,这样大家知道在哪里去找实现函数了)。我们理解模块流程,最好从更高层的抽象角度去考虑,深入到细节是你了解运行机制之后才进行的,否则容易迷失在细节中。通过查找RIL相关联的类(比如它继承的类和实现的接口),在BaseCommands里面找到实现函数:
看看它搞啥了。将传入的GsmCallTracker实例,响应的事件EVENT_CALL_STATE_CHANGE,以及传入的obj(null)包装成了一个Registrant,并且加入列表mCallStateRegistrants中了。注意传入的参数:
在稍微看看Registrant代码,发现就是包装了一下三个传入参数,并且在需要的时候触发事件的发送。mCallStateRegistrants是protected类型,所以可以在其子类RIL里面访问。在processUnsolicited&RIL.java里面确实针对这个做了处理:
是监听到了“RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED”事件,才进行了处理。至于这个事件的发出,涉及到了native层的rild,所以暂不在此提及。
其实就是把这个new AsyncResult(null, null, null)发送到mCallStateRegistrants中每个Registrant中去,并且用实例化Registrant时的handler来处理该AsyncResult。也就是返回到了GsmCallTracker中,注意返回信息的msg.what就是实例化该Registrant时候的what参数,针对来电就是EVENT_CALL_STATE_CHANGE。这个会触发:
也就是将一个mLastRelevantPoll.what = EVENT_POLL_CALL_RESULT的message传入getCurrentCalls函数。
下面来看看RILRequest这个类,非常有意思,它是一个链表实现,应该是作为一个pool的作用。也就是所有的request是放在一个池子里面进行管理(也就是链表,池子比较形象)。需要的时候就obtain一个。
所以通过注释,看起来RILRequest就是容纳用户请求的一个池子。有些朋友可能要问了上面的getCurrentCalls函数直接用send(rr)把整个RILRequest全部发送出去了这是什么情况。记得rr里面还带有mSerial这个值的,这个值就可以定位到是哪个RILRequest被发送了。
send(rr)函数将RILRequest发送到RILSender的处理逻辑里面,由handleMessage进行处理。
还记得我们分析rild的native层的时候,提到的rild的main函数吗?最后会调用RIL_register函数,在这个函数最后会调用:
这个callbacks会用来初始化s_callbacks,而这个RIL_RadioFunctions类型的callbacks是调用rilInit之后返回的值。也既是调用三方的ril库文件,通过初始化返回的callbacks参数作为值来初始化rild层的s_callbacks参数(记住在reference-ril.c里面也有一个s_callbacks变量,但是为static类型,仅在该文件里面才有效)。
所以这个startlisten函数是在指定socket(RIL_SOCKET_1)上进行监听。看看该函数内部实现:
可以看到针对这个fdListen(其实就是rild这个socket的文件描述符,也就是监听rild这个socket)被放到socket_listen-p(其实就是s_ril_param_socket)里面的listen_event这个ril_event中了。
注意,之前我们就在初始化native层的rild的时候就启动了一个ril_event_loop为函数主体的线程。它会监听rild这个套接字,当监听到数据的时候就会在ril_event_loop这个函数里面触发select这个函数,因为rild这个套接字已经放入了readFds这个FD_SET集合了。检测到之后就会触发
所以最后调用的firePending,会直接遍历pending_list列表的每个event,并且调用ev->func(ev->fd, 0, ev->param)直接处理自己。ev->param这个参数实际上是在调用ril_event_set (socket_listen_p->listen_event, fdListen, false, listenCallback, socket_listen_p);时最后一个参数。也就是socket_listen_p,也即是s_ril_param_socket.
在这里监听到这个socket上的变化之后会调用listenCallback来处理。
接收到之后,又将这个fdCommand放入到了readFds里面,进行监听。且触发的是p_info(也即是s_ril_param_socket)的响应函数,就是processCommandsCallback函数。
注意,for循环里面会循环读取p_rs里面的数据,并且将读取出来的p_record传递到processCommandBuffer函数进行处理。
对于当前的RIL_REQUEST_GET_CURRENT_CALLS来说,这个常量值在下面定义:
RILConstants.java:211: int RIL_REQUEST_GET_CURRENT_CALLS = 9;
所以pRI->pCI = &(s_commands[9]);,找到Ril_commands.h中对应id的值为:
所以我们知道后面调用的pRI->pCI->dispatchFunction(p, pRI);是调用哪个函数了。
所以跳转到reference-ril.c里面去了,会执行onRequest方法里面的如下分支:
其实就是通过at_send_command_multiline向modem发送AT命令,并且将结果存储在p_response中。后续会对将其中的内容解析出来,放入pp_calls里面。最后会调用RIL_onRequestComplete(t, RIL_E_SUCCESS, pp_calls, countValidCalls * sizeof (RIL_Call *))。所以,发送RIL_REQUEST_GET_CURRENT_CALLS命令之后,从modem用AT命令查询到的结果pp_calls就被RIL_onRequestComplete函数返回了。
还记得Ril_commands.h里面的数组吗?
pRI->pCI->responseFunction(p, response, responselen);这个函数对应的就是最后的responseCallList函数。该函数在Ril.cpp里面定义。
主要作用就是将response里面所有的电话信息都保存到序列化参数p里面,而这个参数最终会被sendResponse函数发送出去。
下面的blockingWrite就是将数据往fd句柄里面写入,代码如下:
那这个地方的fd是哪里冒出来的呢?是否已经被绕晕了,不要怕,我也晕。但是凡事都有蛛丝马迹,需要的是耐心。我们追根溯源看看这个变量。最近的赋值,是在上一级的sendResponseRaw里面fd = s_ril_param_socket.fdCommand。而s_ril_param_socket是在RIL_register(这个函数大家应该很熟悉了吧,在ril.cpp里面,在rild.c的main函数里面被调用)里面,以引用传递的方式被传递给startListen函数了。而后,在startListen里面该变量被重命名为socket_listen_p,并被二人组加入到多路IO复用机制里面了。
所以当触发的时候,该参数作为param被传到响应函数listenCallback中了。
所以看到这里,大家就知道这个fd其实就是调用accept,响应上层传入的数据之后的socket。所以这blockwriting其实就是将从modem获取的数据写回到上层去。
我们再次回到上层。接受该消息的就是RIL.java里面的内部类RILReceiver,它是一个Runnable类。这个类在RIL的构造函数里面被初始化,并且被另起了一个线程来运行。
所以很明显可以看到,这个线程就是不停的从rild这个socket里面读取值,并且将读取出来的值序列化成parcel类型,最后用processResponse函数处理该值。
在RIL_onRequestComplete函数里面,type类型被定义为RESPONSE_SOLICITED。所以会触发下面一个分支。
我们来分析一下responseCallList函数:
其实就是读取序列化参数p里面的数据,并且实例化为DriverCall对象,并放入response这个列表,且返回该列表。
下面分析如何处理response的代码:
是将一个消息发送给它的target进行处理。注意在函数调用中,rr.mResult.obj被赋值为了这个AsyncResult了。一个消息必包含一个message.what和messag.target(也就是handle)。那我们看看这个消息是怎么来的,其实这个rr是通过serial这个rr的id号在列表中找到的,上面我们也提到过这个id号,它是用来标识唯一的RilRequest的。至于这个rr怎么来的,大家看看下面的代码就知道了。
所以我们知道,这个message的target是CallTracker类或子类,而what参数为EVENT_POLL_CALLS_RESULT。
在实际代码中,以GsmPhone为例,target就换成了GsmCallTracker了。
注意这个msg.obj实际上在AsyncResult.forMessage(rr.mResult, ret, null)中被赋值为了一个AsyncResult了。
这个ret就是通过rild这个套接字从native层接收到的结果解析成数据,并且放入ArrayList response。所以这个ret就是很多DriverCall组成的列表啊。
我们下面看看handlePollCalls函数,看他是如何处理返回结果的。
看看mPhone.notifyNewRingConnection(newRinging)函数,就是在这里通知的。这个mPhone其实就是在GsmPhone的构造函数里面实例化GsmCallTracker的时候传入的。最后辗转调用的是GsmPhone的父类里面的函数。这个有点类似模板方法了哈,把部分逻辑过程放在父类里面实现,它所有的子类都公用这段逻辑。
其实就是调用在列表中的每个Registrant来处理从底层传回来的结果。这个很像观察者模式吧,哈哈,把所有的观察者放在一个列表,等事件来的时候,一一通知。
所以这样来看看这些Registrant是在哪里放入PhoneBase里面这个mNewRingingConnectionRegistrants列表的。经过查找,找到下面的地方。
看起来并不像是这个地方处理,所以扩大到全项目搜索代码,最后在packages目录下的PstnIncomingCallNotifier.java中找到。(这个名字签名的Pstn不知道到底啥意思)
所以该结果被传到TelecomManager里面去了。
这个addNewIncomingCall函数最终调用的是TelecomServiceImpl.java类里面的。其实这些方法是在该类的变量:private final ITelecomService.Stub mBinderImpl = new ITelecomService.Stub()下面实现的。
其实就是将传进来的参数打包成Intent,然后通过CallIntentProcessor.processIncomingCallIntent处理掉。
上文的callsManager是在TelecomServiceImpl的构造函数里面赋值的。而该变量实际是在TelecomSystem.java的构造函数里面赋值的:
注意,CallsManager里面有好多参数都是TelecomSystem实例化的实例化的时候传进来的值。这个TelecomSystem是在TelcomService里面进行实例化的,你看到这个实例化的时候一定会大吃一惊!
这里面定义了一堆匿名内部类,部分内容被传至CallsManager类(注意这里是CallsManager而不是CallManager)。至此,我们总算知道了实例化这个CallsManager实例时,里面存放的到底是些什么内容了。所以我们再回到上面的:
我们先看看CreateConnectionProcessor的简介:
这个类创建一个Connection,这个connection用来放置拨出的电话,或者附着到一个呼入电话上。在两种方式中,这个类会循环编译一系列Connection Services,直到有下列情况发生:
一个connection services返回一个最新创建的connection,因为有一个call被显示给了用户
一个connection service取消了处理进程,call就abort中断了。
因为可以看到上面的 程序中有一个明显的迭代器,所以看看最后一个函数是否对迭代器的数据进行了处理:
其实这个serviceIntent触发的是”android.telecom.ConnectionService”这个Action,在package/Service/Telephony/AndroidManifest.xml里面可以找到对应的service为TelephonyConnectionService。这个mComponentName的值就没有找到在什么地方了。连接成功之后,就会触发connection的onServiceConnected函数了。
这个callback就是在上面createConnection函数中创建的内部类如下:
其实这个mServiceInterface就是绑定ConnectionService的时候反回来的一个IBinder,所以这个引用就是调用的ConnectionService.createConnection了。
这个调用会遍历mAdapter里面的每个IConnectionServiceAdapter,并且执行
而这个mAdapter是通过调用addAdapter函数进行填充的。而这个函数在ConnectionService唯一调用的地方是在mHandler里面,处理MSG_ADD_CONNECTION_SERVICE_ADAPTER消息的时候。注意这个mHandler和mAdapter都是private的,也就是都是仅限这个类内部访问。这个消息是在mBinder的addConnectionServiceAdapter函数里面触发的。
在ConnectionServiceWrapper里面的setServiceInterface里面会调用
这个adapter函数实际定义在:
其实是一个内部类。所以在ConnectionService—createConnection里面调用adapter.handleCreateConnectionComplete(id, request, connection)实际调用的是这个内部类的对应函数。
而通过搜索,发现在call.java里面有对函数handleCreateConnectionSuccess的实现。
请注意看if (mIsIncoming)这个分支里面的注释。当我们正在被连接服务(connection service)验证的时候,我们并不立即处理呼入电话。我们允许来电信息查询代码首先执行,这样我们就可以读取是否转到语音邮箱的属性,这样我们可以决定我们是否将来电显示给用户还是直接拒绝。
我们在看看这个作为mDirectToVoicemailRunnable
会调用mListeners的onSuccessfulIncomingCall函数。
在CallsManagerListener里面,调用里面的onCallAdded如下:
这个会调用InCallService的addCall函数。
注意最后的这个inCallService.addCall(parcelableCall),实际触发了一个消息机制。同时注意,还有一个MSG_SET_IN_CALL_ADAPTER消息会触发将mPhoneListener加入到Phone的监听者列表里面。最终该消息会触发 mPhone.internalAddCall。我们看看这个最后的调用函数fireCallAdded(call):
上面我们也提到了,另外一个消息MSG_SET_IN_CALL_ADAPTER,会将一个监听者mPhoneListener加入到Phone的监听列表里面,所以这个循环遍历列表的行为会触发这个mPhoneListener。
看看上面的,基本上设计到了各种通话属性的变化。而且都是转到InCallService里面进行处理。看看对于onCallAdded的处理。
InCallService里面的onCallAdded是一个空函数,所以会由它的子类来进行处理,它的子类是InCallServiceImpl.java。重点来了,这个子类中的实现为:
我们来看看CallList的onCallAdded函数:
上面讲到了一个细节,CallList实际将InCallPresenter实例保存在了listener列表里面。所以这个onIncoming会触发listener.onIncomingCall(call);这个listener则是InCallPresenter,所以最后调用的是如下:
注意,上面的startOrFinishUi是关键函数,涉及到显示来电接听的UI弹出流程。这个InCallPresenter很像Google提倡的MVP结构里面的Presenter啊!
综上,CallList的onCallAdded函数会触发来电信息的显示。最后发现,在InCallServiceImpl.java里面,在onCallAdded函数里面会触发CallList的对应函数,也就是会触发来电显示。
根据手机网络制式的不同,通常系统中会扩展Phone.java这个类,扩展成GSMPhone和CDMAPhone。这个类主要是抽象整个手机来处理通信过程中与其他模块的交互。我们以GSMPhone为例,分析来电流程如何从底层传递到上层。该分析主要基于代码,所以会比较啰嗦。
以GSMPhone为例,在PhoneFactory类中有实例化该类的方法:
public static Phone getGsmPhone(int phoneId) { Phone phone = TelephonyPluginDelegate.getInstance().makeGSMPhone(sContext,sCommandsInterfaces[phoneId], sPhoneNotifier, phoneId); return phone; }
这个phone的mCi其实使用sCommandInterfaces第phoneId个元素进行初始化。这个数组是为了支持多卡而设置。
sCommandInterfaces的初始化是:
sCommandsInterfaces = new RIL[numPhones];
所以可以知道其实mCi的真实类型就是RIL类。
GSMPhone会构造一个GsmCallTracker,而在GsmCallTracker中就会在构造函数中调用:
mCi.registerForCallStateChanged(this, EVENT_CALL_STATE_CHANGE, null);
其实就是用GsmCallTracker来监听mCi上的电话状态改变EVENT_CALL_STATE_CHANGE啊。注意这个mCi是CommandInterfaces类型(当然实际是RIL类型,这样大家知道在哪里去找实现函数了)。我们理解模块流程,最好从更高层的抽象角度去考虑,深入到细节是你了解运行机制之后才进行的,否则容易迷失在细节中。通过查找RIL相关联的类(比如它继承的类和实现的接口),在BaseCommands里面找到实现函数:
public void registerForCallStateChanged(Handler h, int what, Object obj) { Registrant r = new Registrant (h, what, obj); mCallStateRegistrants.add(r); }
看看它搞啥了。将传入的GsmCallTracker实例,响应的事件EVENT_CALL_STATE_CHANGE,以及传入的obj(null)包装成了一个Registrant,并且加入列表mCallStateRegistrants中了。注意传入的参数:
handler:实际传入的是GsmCallTracker类型,这个类也是handler的子类 what:EVENT_CALL_STATE_CHANGE,需要监听的事件类型
在稍微看看Registrant代码,发现就是包装了一下三个传入参数,并且在需要的时候触发事件的发送。mCallStateRegistrants是protected类型,所以可以在其子类RIL里面访问。在processUnsolicited&RIL.java里面确实针对这个做了处理:
//RIL.java case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED: mCallStateRegistrants.notifyRegistrants(new AsyncResult(null, null, null)); break; //RegistrantList.java private synchronized void internalNotifyRegistrants (Object result, Throwable exception) { for (int i = 0, s = registrants.size(); i < s ; i++) { Registrant r = (Registrant) registrants.get(i); r.internalNotifyRegistrant(result, exception); } }
是监听到了“RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED”事件,才进行了处理。至于这个事件的发出,涉及到了native层的rild,所以暂不在此提及。
其实就是把这个new AsyncResult(null, null, null)发送到mCallStateRegistrants中每个Registrant中去,并且用实例化Registrant时的handler来处理该AsyncResult。也就是返回到了GsmCallTracker中,注意返回信息的msg.what就是实例化该Registrant时候的what参数,针对来电就是EVENT_CALL_STATE_CHANGE。这个会触发:
//handleMessage&GsmCallTracker.java case EVENT_CALL_STATE_CHANGE: pollCallsWhenSafe(); break; //CallTracker.java protected void pollCallsWhenSafe() { if (checkNoOperationsPending()) { mLastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT); mCi.getCurrentCalls(mLastRelevantPoll); } }
也就是将一个mLastRelevantPoll.what = EVENT_POLL_CALL_RESULT的message传入getCurrentCalls函数。
//RIL.java public void getCurrentCalls (Message result) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_CURRENT_CALLS, result); send(rr); }
下面来看看RILRequest这个类,非常有意思,它是一个链表实现,应该是作为一个pool的作用。也就是所有的request是放在一个池子里面进行管理(也就是链表,池子比较形象)。需要的时候就obtain一个。
static RILRequest obtain(int request, Message result) { RILRequest rr = null; synchronized(sPoolSync) { if (sPool != null) { rr = sPool; sPool = rr.mNext; rr.mNext = null; sPoolSize--; } } if (rr == null) { rr = new RILRequest(); } rr.mSerial = sNextSerial.getAndIncrement();//依次递增,request的id。类似数据库里面的默认第一个键值_id rr.mRequest = request;//请求内容,就是RIL_REQUEST_GET_CURRENT_CALLS rr.mResult = result; rr.mParcel = Parcel.obtain();//一个序列化的数据,如下所见,保存request内容和request在池中的id if (result != null && result.getTarget() == null) { throw new NullPointerException("Message target must not be null"); } // first elements in any RIL Parcel rr.mParcel.writeInt(request); rr.mParcel.writeInt(rr.mSerial); return rr; }
所以通过注释,看起来RILRequest就是容纳用户请求的一个池子。有些朋友可能要问了上面的getCurrentCalls函数直接用send(rr)把整个RILRequest全部发送出去了这是什么情况。记得rr里面还带有mSerial这个值的,这个值就可以定位到是哪个RILRequest被发送了。
send(rr)函数将RILRequest发送到RILSender的处理逻辑里面,由handleMessage进行处理。
case EVENT_SEND: try { LocalSocket s; s = mSocket; synchronized (mRequestList) { mRequestList.append(rr.mSerial, rr);//将request添加到一个列表中 } byte[] data; data = rr.mParcel.marshall();//序列化mParcel里面的内容,注意里面包含request类型和request在池中的id rr.mParcel.recycle(); rr.mParcel = null;//release resource // parcel length in big endian dataLength[0] = dataLength[1] = 0; dataLength[2] = (byte)((data.length >> 8) & 0xff); dataLength[3] = (byte)((data.length) & 0xff); s.getOutputStream().write(dataLength);//将数据长度和数据内容发送到mSocket里面,其实就是rild这个socket s.getOutputStream().write(data); }
还记得我们分析rild的native层的时候,提到的rild的main函数吗?最后会调用RIL_register函数,在这个函数最后会调用:
memcpy(&s_callbacks, callbacks, sizeof (RIL_RadioFunctions)); /* Initialize socket1 parameters */ s_ril_param_socket = { RIL_SOCKET_1, /* socket_id */ -1, /* fdListen */ -1, /* fdCommand */ PHONE_PROCESS, /* processName */ &s_commands_event, /* commands_event */ &s_listen_event, /* listen_event */ processCommandsCallback, /* processCommandsCallback */ NULL /* p_rs */ }; startListen(RIL_SOCKET_1, &s_ril_param_socket);
这个callbacks会用来初始化s_callbacks,而这个RIL_RadioFunctions类型的callbacks是调用rilInit之后返回的值。也既是调用三方的ril库文件,通过初始化返回的callbacks参数作为值来初始化rild层的s_callbacks参数(记住在reference-ril.c里面也有一个s_callbacks变量,但是为static类型,仅在该文件里面才有效)。
所以这个startlisten函数是在指定socket(RIL_SOCKET_1)上进行监听。看看该函数内部实现:
//Ril.cpp static void startListen(RIL_SOCKET_ID socket_id, SocketListenParam* socket_listen_p) { fdListen = android_get_control_socket(socket_name);//在init.rc里面找同名的socket ret = listen(fdListen, 4); socket_listen_p->fdListen = fdListen; /* note: non-persistent so we can accept only one connection at a time */ ril_event_set (socket_listen_p->listen_event, fdListen, false,listenCallback, socket_listen_p); rilEventAddWakeup (socket_listen_p->listen_event); }
可以看到针对这个fdListen(其实就是rild这个socket的文件描述符,也就是监听rild这个socket)被放到socket_listen-p(其实就是s_ril_param_socket)里面的listen_event这个ril_event中了。
注意,之前我们就在初始化native层的rild的时候就启动了一个ril_event_loop为函数主体的线程。它会监听rild这个套接字,当监听到数据的时候就会在ril_event_loop这个函数里面触发select这个函数,因为rild这个套接字已经放入了readFds这个FD_SET集合了。检测到之后就会触发
// Check for timeouts processTimeouts(); // Check for read-ready processReadReadies(&rfds, n); // Fire away firePending();
所以最后调用的firePending,会直接遍历pending_list列表的每个event,并且调用ev->func(ev->fd, 0, ev->param)直接处理自己。ev->param这个参数实际上是在调用ril_event_set (socket_listen_p->listen_event, fdListen, false, listenCallback, socket_listen_p);时最后一个参数。也就是socket_listen_p,也即是s_ril_param_socket.
在这里监听到这个socket上的变化之后会调用listenCallback来处理。
static void listenCallback (int fd, short flags, void *param) { SocketListenParam *p_info = (SocketListenParam *)param; fdCommand = accept(fd, (sockaddr *) &peeraddr, &socklen);//注意这里的accept函数,接收了套接字rild上面的事件 if(NULL == sapSocket) { p_info->fdCommand = fdCommand; p_rs = record_stream_new(p_info->fdCommand, MAX_COMMAND_BYTES); p_info->p_rs = p_rs; ril_event_set (p_info->commands_event, p_info->fdCommand, 1, p_info->processCommandsCallback, p_info); rilEventAddWakeup (p_info->commands_event); onNewCommandConnect(p_info->socket_id); } }
接收到之后,又将这个fdCommand放入到了readFds里面,进行监听。且触发的是p_info(也即是s_ril_param_socket)的响应函数,就是processCommandsCallback函数。
static void processCommandsCallback(int fd, short flags, void *param) { for (;;) { /* loop until EAGAIN/EINTR, end of stream, or other error */ ret = record_stream_get_next(p_rs, &p_record, &recordlen); processCommandBuffer(p_record, recordlen, p_info->socket_id); } if (ret == 0 || !(errno == EAGAIN || errno == EINTR)) { rilEventAddWakeup(&s_listen_event); onCommandsSocketClosed(p_info->socket_id); } }
注意,for循环里面会循环读取p_rs里面的数据,并且将读取出来的p_record传递到processCommandBuffer函数进行处理。
static int processCommandBuffer(void *buffer, size_t buflen, RIL_SOCKET_ID socket_id) { RequestInfo *pRI; /* pendingRequestsHook refer to &s_pendingRequests */ RequestInfo** pendingRequestsHook = &s_pendingRequests; p.setData((uint8_t *) buffer, buflen); // status checked at end //注意这个序列化参数的读取顺序跟下面的写入顺序是对应的,所以这个token也就是mSerial了 status = p.readInt32(&request); status = p.readInt32 (&token); pRI->token = token; pRI->pCI = &(s_commands[request]); pRI->socket_id = socket_id; pRI->p_next = *pendingRequestsHook; *pendingRequestsHook = pRI; /* sLastDispatchedToken = token; */ pRI->pCI->dispatchFunction(p, pRI); return 0; } //ril.java--RILRequest--obtain static RILRequest obtain(int request, Message result) { // first elements in any RIL Parcel rr.mParcel.writeInt(request); rr.mParcel.writeInt(rr.mSerial); }
对于当前的RIL_REQUEST_GET_CURRENT_CALLS来说,这个常量值在下面定义:
RILConstants.java:211: int RIL_REQUEST_GET_CURRENT_CALLS = 9;
所以pRI->pCI = &(s_commands[9]);,找到Ril_commands.h中对应id的值为:
{RIL_REQUEST_GET_CURRENT_CALLS, dispatchVoid, responseCallList},
所以我们知道后面调用的pRI->pCI->dispatchFunction(p, pRI);是调用哪个函数了。
static void dispatchVoid (Parcel& p, RequestInfo *pRI) { CALL_ONREQUEST(pRI->pCI->requestNumber, NULL, 0, pRI, pRI->socket_id); } 等价于: s_callbacks.onRequest(pRI->pCI->requestNumber, NULL, 0, pRI, pRI->socket_id)
所以跳转到reference-ril.c里面去了,会执行onRequest方法里面的如下分支:
case RIL_REQUEST_GET_CURRENT_CALLS: requestGetCurrentCalls(data, datalen, t); break; //Reference-ril.c static void requestGetCurrentCalls(void *data __unused, size_t datalen __unused, RIL_Token t) { ATResponse *p_response; ATLine *p_cur; RIL_Call *p_calls; err = at_send_command_multiline ("AT+CLCC", "+CLCC:", &p_response); for (countValidCalls = 0, p_cur = p_response->p_intermediates ; p_cur != NULL ; p_cur = p_cur->p_next ) { err = callFromCLCCLine(p_cur->line, p_calls + countValidCalls); countValidCalls++; } RIL_onRequestComplete(t, RIL_E_SUCCESS, pp_calls, countValidCalls * sizeof (RIL_Call *)); at_response_free(p_response); RIL_requestTimedCallback (sendCallStateChanged, NULL, &TIMEVAL_CALLSTATEPOLL); }
其实就是通过at_send_command_multiline向modem发送AT命令,并且将结果存储在p_response中。后续会对将其中的内容解析出来,放入pp_calls里面。最后会调用RIL_onRequestComplete(t, RIL_E_SUCCESS, pp_calls, countValidCalls * sizeof (RIL_Call *))。所以,发送RIL_REQUEST_GET_CURRENT_CALLS命令之后,从modem用AT命令查询到的结果pp_calls就被RIL_onRequestComplete函数返回了。
extern "C" void RIL_onRequestComplete(RIL_Token t, RIL_Errno e, void *response, size_t responselen) { pRI = (RequestInfo *)t; int fd = s_ril_param_socket.fdCommand; socket_id = pRI->socket_id; if (pRI->cancelled == 0) { Parcel p; //注意这里写入的类型是RESPONSE_SOLICITED,该值在上层的RIL.java的解析函数processResponse里面会读取出来并进行处理的。 p.writeInt32 (RESPONSE_SOLICITED); p.writeInt32 (pRI->token); p.writeInt32 (e); if (response != NULL) { // there is a response payload, no matter success or not. ret = pRI->pCI->responseFunction(p, response, responselen); } sendResponse(p, socket_id); } }
还记得Ril_commands.h里面的数组吗?
{RIL_REQUEST_GET_CURRENT_CALLS, dispatchVoid, responseCallList},
pRI->pCI->responseFunction(p, response, responselen);这个函数对应的就是最后的responseCallList函数。该函数在Ril.cpp里面定义。
主要作用就是将response里面所有的电话信息都保存到序列化参数p里面,而这个参数最终会被sendResponse函数发送出去。
//ril.cpp static int sendResponse (Parcel &p, RIL_SOCKET_ID socket_id) { return sendResponseRaw(p.data(), p.dataSize(), socket_id); } static int sendResponseRaw (const void *data, size_t dataSize, RIL_SOCKET_ID socket_id) { int fd = s_ril_param_socket.fdCommand; uint32_t header; header = htonl(dataSize);//主机数转换成无符号长整型的网络字节顺序,因为马上就要通过Socket传播了 ret = blockingWrite(fd, (void *)&header, sizeof(header)); ret = blockingWrite(fd, data, dataSize); }
下面的blockingWrite就是将数据往fd句柄里面写入,代码如下:
static int blockingWrite(int fd, const void *buffer, size_t len) { written = write (fd, toWrite + writeOffset, len - writeOffset); }
那这个地方的fd是哪里冒出来的呢?是否已经被绕晕了,不要怕,我也晕。但是凡事都有蛛丝马迹,需要的是耐心。我们追根溯源看看这个变量。最近的赋值,是在上一级的sendResponseRaw里面fd = s_ril_param_socket.fdCommand。而s_ril_param_socket是在RIL_register(这个函数大家应该很熟悉了吧,在ril.cpp里面,在rild.c的main函数里面被调用)里面,以引用传递的方式被传递给startListen函数了。而后,在startListen里面该变量被重命名为socket_listen_p,并被二人组加入到多路IO复用机制里面了。
//RIL_register startListen(RIL_SOCKET_1, &s_ril_param_socket); //startListen函数 ril_event_set (socket_listen_p->listen_event, fdListen, false, listenCallback, socket_listen_p);
所以当触发的时候,该参数作为param被传到响应函数listenCallback中了。
static void listenCallback (int fd, short flags, void *param) { SocketListenParam *p_info = (SocketListenParam *)param; fdCommand = accept(fd, (sockaddr *) &peeraddr, &socklen); if(NULL == sapSocket) { p_info->fdCommand = fdCommand;//注意这里的fdCommand是接受上层数据的socket p_info->p_rs = p_rs; ril_event_set (p_info->commands_event, p_info->fdCommand, 1, p_info->processCommandsCallback, p_info); rilEventAddWakeup (p_info->commands_event); onNewCommandConnect(p_info->socket_id); } }
所以看到这里,大家就知道这个fd其实就是调用accept,响应上层传入的数据之后的socket。所以这blockwriting其实就是将从modem获取的数据写回到上层去。
我们再次回到上层。接受该消息的就是RIL.java里面的内部类RILReceiver,它是一个Runnable类。这个类在RIL的构造函数里面被初始化,并且被另起了一个线程来运行。
//RIL.java--RILReceiver--run public void run() { String rilSocket = "rild"; for (;;) { try { s = new LocalSocket(); l = new LocalSocketAddress(rilSocket, LocalSocketAddress.Namespace.RESERVED); s.connect(l); } mSocket = s; try { InputStream is = mSocket.getInputStream(); for (;;) { length = readRilMessage(is, buffer); p = Parcel.obtain(); p.unmarshall(buffer, 0, length); p.setDataPosition(0); processResponse(p); } } }}
所以很明显可以看到,这个线程就是不停的从rild这个socket里面读取值,并且将读取出来的值序列化成parcel类型,最后用processResponse函数处理该值。
private void processResponse (Parcel p) { type = p.readInt(); if (type == RESPONSE_UNSOLICITED) { processUnsolicited (p); } else if (type == RESPONSE_SOLICITED) { RILRequest rr = processSolicited (p); } }
在RIL_onRequestComplete函数里面,type类型被定义为RESPONSE_SOLICITED。所以会触发下面一个分支。
private RILRequest processSolicited (Parcel p) { serial = p.readInt(); error = p.readInt(); RILRequest rr; rr = findAndRemoveRequestFromList(serial); Object ret = null; if (error == 0 || p.dataAvail() > 0) { // either command succeeds or command fails but with data payload try {switch (rr.mRequest) { case RIL_REQUEST_GET_CURRENT_CALLS: ret = responseCallList(p); break; }} } if (error == 0) { if (rr.mResult != null) { AsyncResult.forMessage(rr.mResult, ret, null); rr.mResult.sendToTarget(); } } }
我们来分析一下responseCallList函数:
private Object responseCallList(Parcel p) { ArrayList<DriverCall> response; DriverCall dc; num = p.readInt(); response = new ArrayList<DriverCall>(num); for (int i = 0 ; i < num ; i++) { dc = new DriverCall(); dc.state = DriverCall.stateFromCLCC(p.readInt()); dc.index = p.readInt(); response.add(dc); } Collections.sort(response); return response; }
其实就是读取序列化参数p里面的数据,并且实例化为DriverCall对象,并放入response这个列表,且返回该列表。
下面分析如何处理response的代码:
if (error == 0) { if (rr.mResult != null) { AsyncResult.forMessage(rr.mResult, ret, null); rr.mResult.sendToTarget(); } }
是将一个消息发送给它的target进行处理。注意在函数调用中,rr.mResult.obj被赋值为了这个AsyncResult了。一个消息必包含一个message.what和messag.target(也就是handle)。那我们看看这个消息是怎么来的,其实这个rr是通过serial这个rr的id号在列表中找到的,上面我们也提到过这个id号,它是用来标识唯一的RilRequest的。至于这个rr怎么来的,大家看看下面的代码就知道了。
//CallTracker.java protected void pollCallsWhenSafe() { if (checkNoOperationsPending()) { mLastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT); mCi.getCurrentCalls(mLastRelevantPoll); } } //RIL.java public void getCurrentCalls (Message result) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_CURRENT_CALLS, result); //将这个rr放入列表中了,这个列表用mSerial唯一标识了它的id,这个mSerial也会被传入底层一直到从底层返回,同样也包含了这个mSerial。所以这个是伴随这个RILRequest的整个声明周期的。 send(rr); }
所以我们知道,这个message的target是CallTracker类或子类,而what参数为EVENT_POLL_CALLS_RESULT。
在实际代码中,以GsmPhone为例,target就换成了GsmCallTracker了。
//GsmCallTracker--handleMessage case EVENT_POLL_CALLS_RESULT: ar = (AsyncResult)msg.obj; if (msg == mLastRelevantPoll) { handlePollCalls((AsyncResult)msg.obj); }
注意这个msg.obj实际上在AsyncResult.forMessage(rr.mResult, ret, null)中被赋值为了一个AsyncResult了。
rr.mResult.obj = new AsyncResult(rr.mResult.obj/*userObj*/, ret/*result*/, null/*exception*/);
这个ret就是通过rild这个套接字从native层接收到的结果解析成数据,并且放入ArrayList response。所以这个ret就是很多DriverCall组成的列表啊。
我们下面看看handlePollCalls函数,看他是如何处理返回结果的。
//GsmCallTracker protected synchronized void handlePollCalls(AsyncResult ar) { if (ar.exception == null) { polledCalls = (List)ar.result;//注意这里的赋值 } Connection newRinging = null; //or waiting for (int i = 0, curDC = 0, dcSize = polledCalls.size(); i < mConnections.length; i++) { GsmConnection conn = mConnections[i]; // polledCall list is sparse if (curDC < dcSize) { dc = (DriverCall) polledCalls.get(curDC); } if (conn == null && dc != null) { // Connection appeared in CLCC response that we don't know about // 注意这里是判断是否是MO,也就是拨出电话 if (mPendingMO != null && mPendingMO.compareTo(dc)) { // It's our pending mobile originating call } else {//这就是拨入电话的响应逻辑了。 mConnections[i] = new GsmConnection(mPhone, dc, this, i);//注意这里初始化的GsmConnection Connection hoConnection = getHoConnection(dc); if (hoConnection != null) {//这个是针对SRVCC这种类型的电话,所以也不是 // Single Radio Voice Call Continuity (SRVCC) completed mConnections[i].migrateFrom(hoConnection); // Updating connect time for silent redial cases (ex: Calls are transferred // from DIALING/ALERTING/INCOMING/WAITING to ACTIVE) } else if ( mConnections[i].getCall() == mRingingCall ) { // it's a ringing call,就是这里了 newRinging = mConnections[i]; } } hasNonHangupStateChanged = true; } } if (newRinging != null) { mPhone.notifyNewRingingConnection(newRinging); } updatePhoneState(); if (hasNonHangupStateChanged || newRinging != null || hasAnyCallDisconnected) { mPhone.notifyPreciseCallStateChanged(); } }
看看mPhone.notifyNewRingConnection(newRinging)函数,就是在这里通知的。这个mPhone其实就是在GsmPhone的构造函数里面实例化GsmCallTracker的时候传入的。最后辗转调用的是GsmPhone的父类里面的函数。这个有点类似模板方法了哈,把部分逻辑过程放在父类里面实现,它所有的子类都公用这段逻辑。
//PhoneBase.java public void notifyNewRingingConnectionP(Connection cn) { if (!mIsVoiceCapable) return; AsyncResult ar = new AsyncResult(null/*userObj*/, cn/*result,其实就是mConnections[i] = new GsmConnection(mPhone, dc, this, i)*/, null/*exception*/); mNewRingingConnectionRegistrants.notifyRegistrants(ar); } //AsyncResult.java public /*synchronized*/ void notifyRegistrants(AsyncResult ar) { internalNotifyRegistrants(ar.result, ar.exception); } private synchronized void internalNotifyRegistrants (Object result, Throwable exception) { for (int i = 0, s = registrants.size(); i < s ; i++) { Registrant r = (Registrant) registrants.get(i); r.internalNotifyRegistrant(result, exception); }} 等价为: r.internalNotifyRegistrant(mConnections[i] = new GsmConnection(mPhone, dc, this, i), null);
其实就是调用在列表中的每个Registrant来处理从底层传回来的结果。这个很像观察者模式吧,哈哈,把所有的观察者放在一个列表,等事件来的时候,一一通知。
所以这样来看看这些Registrant是在哪里放入PhoneBase里面这个mNewRingingConnectionRegistrants列表的。经过查找,找到下面的地方。
//CallManager.java-->registerForPhoneStates //这个handler为CallManagerHandler类型。说明从modem返回的值会被该类处理。类型以及在这里指定了 phone.registerForNewRingingConnection(handler, EVENT_NEW_RINGING_CONNECTION,mRegistrantidentifier); //CallManager.java-->CallManagerHandler case EVENT_NEW_RINGING_CONNECTION: Connection c = (Connection) ((AsyncResult) msg.obj).result; int subId = c.getCall().getPhone().getSubId(); if (getActiveFgCallState(subId).isDialing() || hasMoreThanOneRingingCall(subId)) { //当前是否有正在拨打的电话,或者是否有另外一个正在呼入的电话 } else { mNewRingingConnectionRegistrants.notifyRegistrants((AsyncResult) msg.obj); }
看起来并不像是这个地方处理,所以扩大到全项目搜索代码,最后在packages目录下的PstnIncomingCallNotifier.java中找到。(这个名字签名的Pstn不知道到底啥意思)
//从类开头的注释也可以看出来,该类确实用来负责处理拨入的电话PstnIncomingCallNotifier.java /** * Listens to incoming-call events from the associated phone object and notifies Telecom upon each * occurence. One instance of these exists for each of the telephony-based call services. */ final class PstnIncomingCallNotifier { private void registerForNotifications() { Phone newPhone = mPhoneProxy.getActivePhone(); if (newPhone != null) { mPhoneBase = newPhone; mPhoneBase.registerForNewRingingConnection(mHandler, EVENT_NEW_RINGING_CONNECTION, null); } } } 而这个mHandler对EVENT_NEW_RINGING_CONNECTION的处理为: case EVENT_NEW_RINGING_CONNECTION: handleNewRingingConnection((AsyncResult) msg.obj); break; //handleNewRingingConnection private void handleNewRingingConnection(AsyncResult asyncResult) { Log.d(this, "handleNewRingingConnection"); Connection connection = (Connection) asyncResult.result; if (connection != null) { Call call = connection.getCall(); // Final verification of the ringing state before sending the intent to Telecom. if (call != null && call.getState().isRinging()) { sendIncomingCallIntent(connection); } } } /** * Sends the incoming call intent to telecom. */ private void sendIncomingCallIntent(Connection connection) { Bundle extras = null; if (connection.getNumberPresentation() == TelecomManager.PRESENTATION_ALLOWED && !TextUtils.isEmpty(connection.getAddress())) { extras = new Bundle(); Uri uri = Uri.fromParts(PhoneAccount.SCHEME_TEL, connection.getAddress(), null); extras.putParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS, uri); } //将通话connection的地址打包进extras。注意这个ID,EXTRA_INCOMING_CALL_ADDRESS TelecomManager.from(mPhoneProxy.getContext()).addNewIncomingCall(PhoneUtils.makePstnPhoneAccountHandle(mPhoneProxy), extras); //PhoneUtils.makePstnPhoneAccountHandle的返回值类似等价于下面代码 PhoneUtils.makePstnPhoneAccoutnHandle(mPhoneProxy) = new PhoneAccountHandle(TelephonyConnectionService, mPhoneProxy.getSubId()) }
所以该结果被传到TelecomManager里面去了。
((TelecomManager) mPhoneProxy.getContext().getSystemService(Context.TELECOM_SERVICE)).addNewIncomingCall( PhoneAccountHandle, extras); //TelecomManager.java public void addNewIncomingCall(PhoneAccountHandle phoneAccount, Bundle extras) { try { if (isServiceConnected()) { getTelecomService().addNewIncomingCall(phoneAccount, extras == null ? new Bundle() : extras); }}}
这个addNewIncomingCall函数最终调用的是TelecomServiceImpl.java类里面的。其实这些方法是在该类的变量:private final ITelecomService.Stub mBinderImpl = new ITelecomService.Stub()下面实现的。
//TelecomServiceImpl.java @Override public void addNewIncomingCall(PhoneAccountHandle phoneAccountHandle, Bundle extras) { synchronized (mLock) { Log.i(this, "Adding new incoming call with phoneAccountHandle %s", phoneAccountHandle); if (phoneAccountHandle != null && phoneAccountHandle.getComponentName() != null) { try { Intent intent = new Intent(TelecomManager.ACTION_INCOMING_CALL); intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,phoneAccountHandle); intent.putExtra(CallIntentProcessor.KEY_IS_INCOMING_CALL, true); if (extras != null) { intent.putExtra(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS, extras);} CallIntentProcessor.processIncomingCallIntent(mCallsManager, intent);}}}}
其实就是将传进来的参数打包成Intent,然后通过CallIntentProcessor.processIncomingCallIntent处理掉。
//CallIntentProcessor.java static void processIncomingCallIntent(CallsManager callsManager, Intent intent) { PhoneAccountHandle phoneAccountHandle = intent.getParcelableExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE); Bundle clientExtras = null; if (intent.hasExtra(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS)) { clientExtras = intent.getBundleExtra(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS); } callsManager.processIncomingCallIntent(phoneAccountHandle, clientExtras); }
上文的callsManager是在TelecomServiceImpl的构造函数里面赋值的。而该变量实际是在TelecomSystem.java的构造函数里面赋值的:
//TelecomSystem.java public TelecomSystem( Context context,MissedCallNotifier missedCallNotifier,CallerInfoAsyncQueryFactory callerInfoAsyncQueryFactory, HeadsetMediaButtonFactory headsetMediaButtonFactory,ProximitySensorManagerFactory proximitySensorManagerFactory,InCallWakeLockControllerFactory inCallWakeLockControllerFactory, ViceNotifier vicenotifier) { mCallsManager = new CallsManager(mContext,mLock,mContactsAsyncHelper,callerInfoAsyncQueryFactory,mMissedCallNotifier,mPhoneAccountRegistrar,headsetMediaButtonFactory,proximitySensorManagerFactory,inCallWakeLockControllerFactory,mViceNotifier); }
注意,CallsManager里面有好多参数都是TelecomSystem实例化的实例化的时候传进来的值。这个TelecomSystem是在TelcomService里面进行实例化的,你看到这个实例化的时候一定会大吃一惊!
//TelecomService.java new TelecomSystem(context, new MissedCallNotifierImpl(context.getApplicationContext()), new CallerInfoAsyncQueryFactory() {//注意这个数据库查询类,UI上显示的来电人都是通过这个在数据库中匹配的 @Override public CallerInfoAsyncQuery startQuery(int token, Context context, String number, CallerInfoAsyncQuery.OnQueryCompleteListener listener, Object cookie) { Log.i(TelecomSystem.getInstance(), "CallerInfoAsyncQuery.startQuery number=%s cookie=%s", Log.pii(number), cookie); return CallerInfoAsyncQuery.startQuery(token, context, number, listener, cookie); } }, new HeadsetMediaButtonFactory() { @Override public HeadsetMediaButton create(Context context, CallsManager callsManager, TelecomSystem.SyncRoot lock) { return new HeadsetMediaButton(context, callsManager, lock); } }, new ProximitySensorManagerFactory() { @Override public ProximitySensorManager create(Context context, CallsManager callsManager) { return new ProximitySensorManager(context, callsManager); } }, new InCallWakeLockControllerFactory() { @Override public InCallWakeLockController create(Context context, CallsManager callsManager) { return new InCallWakeLockController(context, callsManager); } }, new ViceNotifier() { @Override public ViceNotificationImpl create(Context context, CallsManager callsManager) { return new ViceNotificationImpl(context.getApplicationContext(), callsManager); } })
这里面定义了一堆匿名内部类,部分内容被传至CallsManager类(注意这里是CallsManager而不是CallManager)。至此,我们总算知道了实例化这个CallsManager实例时,里面存放的到底是些什么内容了。所以我们再回到上面的:
//CallIntentProcessor.java callsManager.processIncomingCallIntent(phoneAccountHandle, clientExtras); //CallsManager.java void processIncomingCallIntent(PhoneAccountHandle phoneAccountHandle, Bundle extras) { Uri handle = extras.getParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS); Call call = new Call(mContext,this,mLock,mConnectionServiceRepository, mContactsAsyncHelper,mCallerInfoAsyncQueryFactory, handle,//其实这个就是地址或者来电号码。从Connection里面获取的,见之前的代码 null /* gatewayInfo */,null /* connectionManagerPhoneAccount */, phoneAccountHandle,true /* isIncoming */,false /* isConference */); call.setIntentExtras(extras); call.addListener(this); call.startCreateConnection(mPhoneAccountRegistrar); } //packages\services\telecomm\src\com\android\server\telecom\Call.java void startCreateConnection(PhoneAccountRegistrar phoneAccountRegistrar) { mCreateConnectionProcessor = new CreateConnectionProcessor(this, mRepository, this, phoneAccountRegistrar, mContext);/*mRepository-- CallsManager.java mConnectionServiceRepository =new ConnectionServiceRepository(mPhoneAccountRegistrar, mContext, mLock, this);*/ mCreateConnectionProcessor.process(); } //CreateConnectionProcessor.java void process() { mAttemptRecords = new ArrayList<>(); if (mCall.getTargetPhoneAccount() != null) { mAttemptRecords.add(new CallAttemptRecord(mCall.getTargetPhoneAccount(), mCall.getTargetPhoneAccount())); } adjustAttemptsForConnectionManager(); adjustAttemptsForEmergency(); mAttemptRecordIterator = mAttemptRecords.iterator(); attemptNextPhoneAccount(); }
我们先看看CreateConnectionProcessor的简介:
这个类创建一个Connection,这个connection用来放置拨出的电话,或者附着到一个呼入电话上。在两种方式中,这个类会循环编译一系列Connection Services,直到有下列情况发生:
一个connection services返回一个最新创建的connection,因为有一个call被显示给了用户
一个connection service取消了处理进程,call就abort中断了。
因为可以看到上面的 程序中有一个明显的迭代器,所以看看最后一个函数是否对迭代器的数据进行了处理:
//CreateConnectionProcessor.java private void attemptNextPhoneAccount() { CallAttemptRecord attempt = null; if (mAttemptRecordIterator.hasNext()) { attempt = mAttemptRecordIterator.next(); } if (mResponse != null && attempt != null) { PhoneAccountHandle phoneAccount = attempt.connectionManagerPhoneAccount; ConnectionServiceWrapper service = mRepository.getService(phoneAccount.getComponentName(), phoneAccount.getUserHandle()); if (service == null) {} else { mCall.setConnectionManagerPhoneAccount(attempt.connectionManagerPhoneAccount); mCall.setTargetPhoneAccount(attempt.targetPhoneAccount); mCall.setConnectionService(service); setTimeoutIfNeeded(service, attempt); service.createConnection(mCall, new Response(service)); }}} //ConnectionServiceWrapper.java void createConnection(final Call call, final CreateConnectionResponse response) { BindCallback callback = new BindCallback() {注意,这个callback就是在下面连接服务成功时候,会触发自己的onSuccess函数}; mBinder.bind(callback, call); } //ServiceBinder.java 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); }}}}
其实这个serviceIntent触发的是”android.telecom.ConnectionService”这个Action,在package/Service/Telephony/AndroidManifest.xml里面可以找到对应的service为TelephonyConnectionService。这个mComponentName的值就没有找到在什么地方了。连接成功之后,就会触发connection的onServiceConnected函数了。
//ServiceBinder&ServiceBinderConnection public void onServiceConnected(ComponentName componentName, IBinder binder) { synchronized (mLock) { mServiceConnection = this; setBinder(binder); handleSuccessfulConnection(); }} private void handleSuccessfulConnection() { for (BindCallback callback : mCallbacks) { callback.onSuccess(); } }
这个callback就是在上面createConnection函数中创建的内部类如下:
//ConnectionServiceWrapper.java--createConnection BindCallback callback = new BindCallback() { 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()); } try { mServiceInterface.createConnection(call.getConnectionManagerPhoneAccount(),callId, new ConnectionRequest(call.getTargetPhoneAccount(),call.getHandle(),extras,call.getVideoState()), call.isIncoming(), call.isUnknown()); } }};
其实这个mServiceInterface就是绑定ConnectionService的时候反回来的一个IBinder,所以这个引用就是调用的ConnectionService.createConnection了。
//ConnectionService---createConnection private void createConnection(final PhoneAccountHandle callManagerAccount,final String callId, final ConnectionRequest request,boolean isIncoming,boolean isUnknown) { Connection connection = onCreateIncomingConnection(callManagerAccount, request); Uri address = connection.getAddress(); mAdapter.handleCreateConnectionComplete(callId,request,new ParcelableConnection()); }
这个调用会遍历mAdapter里面的每个IConnectionServiceAdapter,并且执行
adapter.handleCreateConnectionComplete(id, request, connection);
而这个mAdapter是通过调用addAdapter函数进行填充的。而这个函数在ConnectionService唯一调用的地方是在mHandler里面,处理MSG_ADD_CONNECTION_SERVICE_ADAPTER消息的时候。注意这个mHandler和mAdapter都是private的,也就是都是仅限这个类内部访问。这个消息是在mBinder的addConnectionServiceAdapter函数里面触发的。
在ConnectionServiceWrapper里面的setServiceInterface里面会调用
//ConnectionServiceWrapper,setServiceInterface mServiceInterface = IConnectionService.Stub.asInterface(binder); addConnectionServiceAdapter(mAdapter); private void addConnectionServiceAdapter(IConnectionServiceAdapter adapter) { if (isServiceValid("addConnectionServiceAdapter")) { mServiceInterface.addConnectionServiceAdapter(adapter); }}
这个adapter函数实际定义在:
//ConnectionServiceWrapper.java final class ConnectionServiceWrapper extends ServiceBinder { private final class Adapter extends IConnectionServiceAdapter.Stub {
其实是一个内部类。所以在ConnectionService—createConnection里面调用adapter.handleCreateConnectionComplete(id, request, connection)实际调用的是这个内部类的对应函数。
//ConnectionServiceWrapper.java---Adapter---handleCreateConnectionComplete public void handleCreateConnectionComplete(String callId,ConnectionRequest request,ParcelableConnection connection) { if (mCallIdMapper.isValidCallId(callId)) ConnectionServiceWrapper.this.handleCreateConnectionComplete(callId, request, connection); } private void handleCreateConnectionComplete(String callId,ConnectionRequest request,ParcelableConnection connection) { if (connection.getState() == Connection.STATE_DISCONNECTED) { } else { // Successful connection if (mPendingResponses.containsKey(callId)) { mPendingResponses.remove(callId).handleCreateConnectionSuccess(mCallIdMapper, connection); }}}
而通过搜索,发现在call.java里面有对函数handleCreateConnectionSuccess的实现。
public void handleCreateConnectionSuccess(CallIdMapper idMapper, ParcelableConnection connection) { setTargetPhoneAccount(connection.getPhoneAccount()); setHandle(connection.getHandle(), connection.getHandlePresentation()); //设置显示呼叫者名字 setCallerDisplayName(connection.getCallerDisplayName(), connection.getCallerDisplayNamePresentation()); setConnectionCapabilities(connection.getConnectionCapabilities()); setVideoProvider(connection.getVideoProvider()); setVideoState(connection.getVideoState()); setRingbackRequested(connection.isRingbackRequested()); setIsVoipAudioMode(connection.getIsVoipAudioMode()); setStatusHints(connection.getStatusHints()); setExtras(connection.getExtras()); if (mIsUnknown) { } else if (mIsIncoming) { // We do not handle incoming calls immediately when they are verified by the connection // service. We allow the caller-info-query code to execute first so that we can read the // direct-to-voicemail property before deciding if we want to show the incoming call to // the user or if we want to reject the call. mDirectToVoicemailQueryPending = true; // Timeout the direct-to-voicemail lookup execution so that we dont wait too long before // showing the user the incoming call screen. mHandler.postDelayed(mDirectToVoicemailRunnable, Timeouts.getDirectToVoicemailMillis( mContext.getContentResolver())); } else { for (Listener l : mListeners) { l.onSuccessfulOutgoingCall(this,getStateFromConnectionState(connection.getState())); } } }
请注意看if (mIsIncoming)这个分支里面的注释。当我们正在被连接服务(connection service)验证的时候,我们并不立即处理呼入电话。我们允许来电信息查询代码首先执行,这样我们就可以读取是否转到语音邮箱的属性,这样我们可以决定我们是否将来电显示给用户还是直接拒绝。
我们在看看这个作为mDirectToVoicemailRunnable
//Call.java private final Runnable mDirectToVoicemailRunnable = new Runnable() { public void run() { synchronized (mLock) { processDirectToVoicemail(); }}}; private void processDirectToVoicemail() { if (mDirectToVoicemailQueryPending) { if (mCallerInfo != null && mCallerInfo.shouldSendToVoicemail) { setState(CallState.RINGING, "directing to voicemail"); reject(false, null); } else { for (Listener l : mListeners) { l.onSuccessfulIncomingCall(this); } } mDirectToVoicemailQueryPending = false; } }
会调用mListeners的onSuccessfulIncomingCall函数。
//CallsManager.java public void onSuccessfulIncomingCall(Call incomingCall) { setCallState(incomingCall, CallState.RINGING, "successful incoming call"); if (hasMaximumRingingCalls(incomingCall.getTargetPhoneAccount().getId()) || hasMaximumDialingCalls() ) { incomingCall.reject(false, null); // since the call was not added to the list of calls, we have to call the missed // call notifier and the call logger manually. mMissedCallNotifier.showMissedCallNotification(incomingCall); mCallLogManager.logCall(incomingCall, Calls.MISSED_TYPE); } else { if(TelephonyManager.getDefault().getMultiSimConfiguration()== TelephonyManager.MultiSimVariants.DSDA) { incomingCall.mIsActiveSub = true; } addCall(incomingCall); setActiveSubscription(incomingCall.getTargetPhoneAccount().getId()); }} private void addCall(Call call) { call.addListener(this); mCalls.add(call); // TODO: Update mForegroundCall prior to invoking // onCallAdded for calls which immediately take the foreground (like the first call). for (CallsManagerListener listener : mListeners) { listener.onCallAdded(call); } updateCallsManagerState(); }
在CallsManagerListener里面,调用里面的onCallAdded如下:
//InCallController.java这个类实现了CallsManagerListenerBase这个类,所以看看这个的onCallAdded public void onCallAdded(Call call) { if (!isBoundToServices()) {//在成功绑定了服务之后,这个函数返回值应该就是true了,所以应该走另外一个分支 bindToServices(call); } else { Log.i(this, "onCallAdded: %s", call); // Track the call if we don't already know about it. addCall(call); for (Map.Entry<ComponentName, IInCallService> entry : mInCallServices.entrySet()) { ComponentName componentName = entry.getKey(); IInCallService inCallService = entry.getValue(); ParcelableCall parcelableCall = toParcelableCall(call, true /* includeVideoProvider */); try { inCallService.addCall(parcelableCall); } catch (RemoteException ignored) { }}}}
这个会调用InCallService的addCall函数。
//InCallService.java public void addCall(ParcelableCall call) { mHandler.obtainMessage(MSG_ADD_CALL,call).sendToTarget(); } case MSG_SET_IN_CALL_ADAPTER: mPhone = new Phone(newInCallAdapter((IInCallAdapter) msg.obj)); mPhone.addListener(mPhoneListener); onPhoneCreated(mPhone); break; case MSG_ADD_CALL: mPhone.internalAddCall((ParcelableCall) msg.obj); break; //Phone.java final void internalAddCall(ParcelableCall parcelableCall) { Call call = new Call(this, parcelableCall.getId(), mInCallAdapter,parcelableCall.getState(), parcelableCall.isActive()); mCallByTelecomCallId.put(parcelableCall.getId(), call); mCalls.add(call); checkCallTree(parcelableCall); call.internalUpdate(parcelableCall,mCallByTelecomCallId); fireCallAdded(call); }
注意最后的这个inCallService.addCall(parcelableCall),实际触发了一个消息机制。同时注意,还有一个MSG_SET_IN_CALL_ADAPTER消息会触发将mPhoneListener加入到Phone的监听者列表里面。最终该消息会触发 mPhone.internalAddCall。我们看看这个最后的调用函数fireCallAdded(call):
//Phone.java private void fireCallAdded(Call call) { for (Listener listener : mListeners) { listener.onCallAdded(this, call); } }
上面我们也提到了,另外一个消息MSG_SET_IN_CALL_ADAPTER,会将一个监听者mPhoneListener加入到Phone的监听列表里面,所以这个循环遍历列表的行为会触发这个mPhoneListener。
//InCallService.java private Phone.Listener mPhoneListener = new Phone.Listener() { public void onAudioStateChanged(Phone phone, AudioState audioState) {} public void onCallAudioStateChanged(Phone phone, CallAudioState callAudioState) { InCallService.this.onCallAudioStateChanged(callAudioState);}; public void onBringToForeground(Phone phone, boolean showDialpad) { InCallService.this.onBringToForeground(showDialpad);} public void onCallAdded(Phone phone, Call call) { InCallService.this.onCallAdded(call);} public void onCallRemoved(Phone phone, Call call) { InCallService.this.onCallRemoved(call);} public void onCanAddCallChanged(Phone phone, boolean canAddCall) { InCallService.this.onCanAddCallChanged(canAddCall);} };
看看上面的,基本上设计到了各种通话属性的变化。而且都是转到InCallService里面进行处理。看看对于onCallAdded的处理。
InCallService里面的onCallAdded是一个空函数,所以会由它的子类来进行处理,它的子类是InCallServiceImpl.java。重点来了,这个子类中的实现为:
//InCallServiceImpl public class InCallServiceImpl extends InCallService{ public void onCallAdded(Call call) { CallList.getInstance().onCallAdded(call); InCallPresenter.getInstance().onCallAdded(call); }}
我们来看看CallList的onCallAdded函数:
//CallList.java ublic void onCallAdded(android.telecom.Call telecommCall) { Call call = new Call(telecommCall); if (call.getState() == Call.State.INCOMING ||call.getState() == Call.State.CALL_WAITING) { onIncoming(call, call.getCannedSmsResponses()); } else { onUpdate(call); } } public void onIncoming(Call call, List<String> textMessages) { for (Listener listener : mListeners) { listener.onIncomingCall(call); } }
上面讲到了一个细节,CallList实际将InCallPresenter实例保存在了listener列表里面。所以这个onIncoming会触发listener.onIncomingCall(call);这个listener则是InCallPresenter,所以最后调用的是如下:
//InCallPresenter.java public void onIncomingCall(Call call) { InCallState newState = startOrFinishUi(InCallState.INCOMING); InCallState oldState = mInCallState; mInCallState = newState; for (IncomingCallListener listener : mIncomingCallListeners) { listener.onIncomingCall(oldState, mInCallState, call); } if (InCallServiceImpl.isDsdaEnabled() && (mInCallActivity != null)) { mInCallActivity.updateDsdaTab(); } }
注意,上面的startOrFinishUi是关键函数,涉及到显示来电接听的UI弹出流程。这个InCallPresenter很像Google提倡的MVP结构里面的Presenter啊!
综上,CallList的onCallAdded函数会触发来电信息的显示。最后发现,在InCallServiceImpl.java里面,在onCallAdded函数里面会触发CallList的对应函数,也就是会触发来电显示。
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories