收藏 分销(赏)

Android通话过程分析.docx

上传人:a199****6536 文档编号:6990453 上传时间:2024-12-24 格式:DOCX 页数:11 大小:306.68KB 下载积分:8 金币
下载 相关 举报
Android通话过程分析.docx_第1页
第1页 / 共11页
Android通话过程分析.docx_第2页
第2页 / 共11页


点击查看更多>>
资源描述
Android通话过程分析 本文档主要对android平台下的call的实现做详细分析。 Call处理的五大核心分别是:Call,Phone, CallTracker,DriverCall,Connection 1. Call Call是Call应用中的最基本的单位,其主要是用来管理Connection的。Call中非常重要的是其状态,Call中共有九种状态: IDLE, ACTIVE, HOLDING, DIALING, ALERTING, INCOMING, WAITING, DISCONNECTED, DISCONNECTING; 对call的处理实际上是对状态转换上的处理。对这九中状态所对应的含义和call此时的现状要很熟。 Call的继承关系图: Call是一个抽象类,从图中可知,实际操作是在其子类GsmCall和CdmaCall。在GsmCall中,有个成员变量:connections,这个变量是用来管理Call中的connection的,一个Call最大允许有5个connections: static final int MAX_CONNECTIONS_PER_CALL = 5; // only 5 connections allowed per call 2. Phone Phone不仅是call的处理核心,而且是整个Telephony处理的核心。Phone是一个最基本的概念,用来控制Phone系统相关(即无线相关的)模块的处理:simcard,call,message,datacall等。 Phone的继承关系如下: 在Phone的继承关系中可知,Phone只是一个接口,它被PhoneBase和PhoneProxy实现,而PhoneBase是抽象类,它被GsmPhone和CdmaPhone继承。所以有此可知Phone分为两类:GsmPhone和CdmaPhone。 PhoneBase还有另外一个继承关系:继承自Handler。这就说明GsmPhone和CdmaPhone其实都是一个Handler。所以PhoneBase的子类是可以进行事件处理的。 3. Connection Connection用来处理一个真正的通话通路,包含通话过程中call的数据,包括号码、通话时间、MT还是MO、是第几路通话、挂断原因等信息。 Connection类关系图: GsmConnection中有个成员变量:GsmCall parent,这个成员变量是用来表示该connection是属于哪个Call的。由变量名(parent)可以看出Call与Connection的关系:父与子的关系,一个Call可以有多个Connection(3gpp中规定最多5个),但一个Connection只能属于一个Call。 所以一个Connection必定要依附于一个Call。Connection是怎样依附于一个Call的呢?从Connection的构造方法中就可以知道: a. GsmConnection (Context context, DriverCall dc, GsmCallTracker ct, int index) 这个构造方法是在MT的时候使用的,因为它有一个DriverCall的参数。它通过parentFromDCState方法来获得对应的parent(Call)且通过parent.attach(this, dc);把connection加入到Call的Connections变量进行管理。 b. GsmConnection (Context context, String dialString, GsmCallTracker ct, GsmCall parent) 这个构造方法是在MO的时候使用的,它会传入一个指定的parent(Call)且通过parent.attachFake(this, GsmCall.State.DIALING);调用把Connection加入到Call的Connections变量进行管理。 从上面知道Connection调用了Call的2个重要的方法:Attach和attachFake。这两个方法都是把一个connection加入到Call的Connections成员变量中进行管理的。Call中还有一个方法detach(GsmConnection conn),这个方法是用来把connection从Call中移除的。 其中还有一个方法:/*package*/ boolean update (DriverCall dc)。这个是用来更新connection的。 4. DriverCall 是与ril层通信时的一个中间处理类,主要用来接收到ril的call数据后转到到java层上来。 DriverCall中包含了协议中规定的有关call的相关参数,具体如下: public int index; //Connection Index for use with, eg, AT+CHLD public boolean isMT; //是incoming还是outgoing public State state; //connection state。 public boolean isMpty;// nonzero if is mpty call。 public String number;// Remote party number public int TOA; //type of address, eg 145 = intl public boolean isVoice;// nonzero if this is is a voice call public boolean isVoicePrivacy;// nonzero if CDMA voice privacy mode is active public int als;// ALS line indicator if available (0 = line 1) public int numberPresentation;// 0=Allowed, 1=Restricted, 2=Not Specified/Unknown 3=Payphone public String name;// Remote party name public int namePresentation;// 0=Allowed, 1=Restricted, 2=Not Specified/Unknown 3=Payphone 5. CallTracker CallTracker的类关系图: 从上图中可以看到,CallTracker 在本质上是一个Handler。 CallTracker是一个抽象类,所以其实际的操作对象是其子类:GSMCallTracker和CdmaCallTracker。 下面以GSMCallTracker为例介绍CallTracker的相关处理,CdmaCallTracker处理基本与之相同。 GSMCallTracker是Android 的通话管理层。GSMCallTracker建立了ConnectionList 来管理现行的通话连接,并向上层提供电话调用接口。 1) Connections Connections是GSMCallTracker 用来维护所有的通话的列表,最大可维护7路通话。 static final int MAX_CONNECTIONS = 7; // only 7 connections allowed in GSM 2) ringingCall、foregroundCall、backgroundCall 一个手机系统只允许3个Call同时存在,即ring call、active call和held call,所以GSMCallTracker用ringingCall、foregroundCall、backgroundCall来管理。 ringingCall:用来管理INCOMING和WAITING的通话 foregroundCall:用来管理DAILING、ALERTING、ACTIVE的通话 backgroundCall:用来管理HOLD的通话 那么,ringingCall、foregroundCall、backgroundCall是如何来管理对应的call和connection的呢?前面已经讲过了Call和Connection及它们之间的关系,其实系统中的Call是已经存在的,就是上面的3个,其实主要的是对于一个connection,它需要依附于那个call,由connection的构造方法知: 1) 在 从RIL获取的Calls列表的时候,通过parentFromDCState来获取相应的Call: private GsmCall parentFromDCState (DriverCall.State state) { switch (state) { case ACTIVE: case DIALING: case ALERTING: return owner.foregroundCall; //break; case HOLDING: return owner.backgroundCall; //break; case INCOMING: case WAITING: return owner.ringingCall; //break; default: throw new RuntimeException("illegal call state: " + state); } } 2) 在其他情况下,一般根据上面的状态直接传入对应的call。 3) GsmCallTracker中的事件处理机制 Call的事件处理基本上是请求应答模式,具体如下(以dail为例,其他类同): 其中涉及到3个变量的处理: protected int pendingOperations; protected boolean needsPoll; protected Message lastRelevantPoll; pendingOperations:顾名思义,这个变量是在发生请求的时候会++,在处理应答的时候会--。 needsPoll:该变量是用来配合pendingOperations处理是否需要从RIL获取当前calls列表,并更新connections列表。 lastRelevantPoll:在发送RIL_REQUEST_GET_CURRENT_CALLS的时候记录最近一次请求的message,在response的时候只对最近一次请求的response做出响应,更新connections列表。 上面的3个变量主要是用来判断是否需要发送RIL_REQUEST_GET_CURRENT_CALLS请求来从RIL获取当前的calls列表,并更新connections列表。 GsmCallTracker事件处理的核心是一个异步事件的处理,在发送请求后等待回应的时候,用户有可能会继续的发送对应的请求,然后会有多个response同时上报过来,上面的3个变量主要是为了更好的处理这种情况,不管用户发送了多少次请求,pendingOperations都会记录下来;而且只要用户发送了一次请求,needsPoll就为true,即就需要从RIL获取最新的call列表。所以只有当pendingOperations==0 并且 needsPoll == true的时候才发送RIL_REQUEST_GET_CURRENT_CALLS请求去获取Calls列表。 if (pendingOperations == 0 && needsPoll) { lastRelevantPoll= obtainMessage(EVENT_POLL_CALLS_RESULT); cm.getCurrentCalls(lastRelevantPoll); } 由于中间可能发送了多次RIL_REQUEST_GET_CURRENT_CALLS请求,在多次发送此请求的过程中却没有一次response回来,最后的结果是到最后肯定会有多个response上来,而此时我们只需要更新一次就够了,lastRelevantPoll就是用来处理这个事情的:lastRelevantPoll记录了最近一次发送RIL_REQUEST_GET_CURRENT_CALLS请求时的response message,当返回的response message是最后一个时就更新Connections列表。 4) GsmCallTracker的核心处理方法----更新connections列表处理方法 protected void handlePollCalls(AsyncResult ar)的处理分析 handlePollCalls(AsyncResult ar) { List polledCalls; if(DBG_POLL) log(">handlePollCalls"); if (ar.exception == null) { //没有异常,取得calllists列表 polledCalls = (List)ar.result; } else if (isCommandExceptionRadioNotAvailable(ar.exception)) { //如果radio是RADIO_NOT_AVAILABLE,则挂断所有的calls,这里的意思是所有的DriverCall是null。 polledCalls = new ArrayList(); } else { //其他的异常的话,推迟POLL_DELAY_MSEC = 250后再发送//RIL_REQUEST_GET_CURRENT_CALLS去获取DriverCall列表。 pollCallsAfterDelay(); return; } Connection newRinging = null; //or waiting boolean hasNonHangupStateChanged = false; // Any change besides // a dropped connection boolean needsPollDelay = false; boolean unknownConnectionAppeared = false; //遍历DriverCall和Connections,根据不同情况做相应处理。 for (int i = 0, curDC = 0, dcSize = polledCalls.size() ; i < connections.length; i++) { GsmConnection conn = connections[i]; DriverCall dc = null; // polledCall list is sparse if (curDC < dcSize) { dc = (DriverCall) polledCalls.get(curDC); //此处说明connections数组的index+1就是callId,也即dc.index。 if (dc.index == i+1) { curDC++; } else { dc = null; } } if (conn == null && dc != null) { //conn为null,说明CallTracker中是没有对应的call的,这只有两种情况可以//发生:MO的dialing状态和MT的incoming/waiting状态。打电话和来电的时候//会执行到此处。 } else if (conn != null && dc == null) { //说明在底层已经挂掉了,CallTracker需要drop该connection。对方挂断电话//的时候就会执行到此处。 } else if (conn != null && dc != null && !pareTo(dc)) { //此处说明对应的connection和dc并不是同一个call,这种情况下就需要drop //当前的connection并根据dc重新构建一个。此处应该是一个异常的处理情况。 } else if (conn != null && dc != null) { //此处表明connection和dc是同一个call,随后根据dc来更新connection。 } if (REPEAT_POLLING) {} } if (pendingMO != null) { //此时dial请求已经发送给ril但是对应的response还没有上来的情况。正常情况//下,到此时pengdingMO应该为null了,但是假如在dial后的response还没有上//来的时候做了其他动作,如hangup call,则此时很可能就执行到此处。 droppedDuringPoll.add(pendingMO); pendingMO = null; hangupPendingMO = false; } if (newRinging != null) { //表示是一个MT call,需要通知用户。 phone.notifyNewRingingConnection(newRinging); } // clear the "local hangup" and "missed/rejected call" // cases from the "dropped during poll" list // These cases need no "last call fail" reason for (int i = droppedDuringPoll.size() - 1; i >= 0 ; i--) { GsmConnection conn = droppedDuringPoll.get(i); if (conn.isIncoming() && conn.getConnectTime() == 0) { // Missed or rejected call Connection.DisconnectCause cause; if (conn.cause == Connection.DisconnectCause.LOCAL) { cause = Connection.DisconnectCause.INCOMING_REJECTED; } else { cause = Connection.DisconnectCause.INCOMING_MISSED; } droppedDuringPoll.remove(i); conn.onDisconnect(cause); } else if (conn.cause == Connection.DisconnectCause.LOCAL) { // Local hangup droppedDuringPoll.remove(i); conn.onDisconnect(Connection.DisconnectCause.LOCAL); } else if (conn.cause == Connection.DisconnectCause.INVALID_NUMBER) { droppedDuringPoll.remove(i); conn.onDisconnect(Connection.DisconnectCause.INVALID_NUMBER); } } // Any non-local disconnects: determine cause if (droppedDuringPoll.size() > 0) { //本地挂断都是DisconnectCause.LOCAL,此处表明是对方或网络端的挂断,具体//挂断原因需要从RIL处获得。 cm.getLastCallFailCause( obtainNoPollCompleteMessage(EVENT_GET_LAST_CALL_FAIL_CAUSE)); } if (needsPollDelay) { pollCallsAfterDelay(); } // Cases when we can no longer keep disconnected Connection's // with their previous calls // 1) the phone has started to ring // 2) A Call/Connection object has changed state... // we may have switched or held or answered (but not hung up) if (newRinging != null || hasNonHangupStateChanged) { internalClearDisconnected(); } 更新Phone的状态。 updatePhoneState(); if (unknownConnectionAppeared) { phone.notifyUnknownConnection(); } if (hasNonHangupStateChanged || newRinging != null) { //通知用户callstatechange。 phone.notifyPreciseCallStateChanged(); } if(DBG_POLL) log("<handlePollCalls"); //dumpState(); } Call处理中的内部接口就是PhoneUtils,它提供的主要接口如下: setAudioControlState(int) answerCall(Phone) hangup(Phone) hangupRingingCall(Phone) hangupActiveCall(Phone) hangupHoldingCall(Phone) hangupRingingAndActive(Phone) hangupAllCalls(Phone) hangup(Call) hangupAllConnections(Call) hangup(Connection) answerAndEndHolding(Phone) answerAndEndActive(Phone) placeCall(Phone, String, Uri) placeCallVia(Context, Phone, String, Uri, Uri) switchHoldingAndActive(Phone) mergeCalls(Phone) isConferenceCall(Call) showIncomingCallUi(int) turnOnSpeaker(Context, boolean, boolean) restoreSpeakerMode(Context) isSpeakerOn(Context) turnOnNoiseSuppression(Context, boolean, boolean) restoreNoiseSuppression(Context) setMute(Phone, boolean) getMute(Phone) setAudioMode(Context, int) okToS(Phone) okToMergeCalls(Phone) okToAddCall(Phone) 外部进程或应用需要使用call时,如hardware键接听和挂断电话等,此时的接口是PhoneInterfaceManager类所提供,此类继承自ITelephony.Stub,是aidl接口。 PhoneUtils中有一个static子类:ConnectionHandler,其主要是用来处理Mute设置相关的,其中主要是更新sConnectionMuteTable并根据当前phone的状态来控制mute设置。
展开阅读全文

开通  VIP会员、SVIP会员  优惠大
下载10份以上建议开通VIP会员
下载20份以上建议开通SVIP会员


开通VIP      成为共赢上传

当前位置:首页 > 包罗万象 > 大杂烩

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2026 宁波自信网络信息技术有限公司  版权所有

客服电话:0574-28810668  投诉电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服