Android启用GPRS成功后反馈流程(MTK)
2015-03-03 10:02
483 查看
看此篇看不太懂的同志们可以先看看我另一篇文章:http://blog.csdn.net/yankebin/article/details/44035489
理解了建立GPRS通信的流程再来看这篇文章就相对来说好理解了
android通信流程本身就是一个很复杂的问题,我只是以我工作过程中遇到的细节为主要线索,理一理整个过程中需要注意的地方,如有错误和不当,还望大家海涵和指正。
(1).先回过头来看看数据网络开启过程中的CdmaDataConnection和GsmDataConnection中的onConnect()方法,该方法中在调用RIL的setupDataCall()时,传入了标识为EVENT_SETUP_DATA_CONNECTION_DONE 的Message,在RIL的setupDataCall()使用该Message获取了RILRequest的实例并将该message作为RIL Parcel的第一个元素写入到其中。
RILRequest rr = RILRequest. obtain(RIL_REQUEST_SETUP_DATA_CALL, result);
该obtain方法作用是从池中检索一个新的RILRequest实例,第一个参数是定义在RILConstants中以RIL_REQUEST_打头的整型值,第二个参数是操作完成后要发送的东西。由此看来之前标识EVENT_SETUP_DATA_CONNECTION_DONE 的Message会在执行完后将发送出去。RILRequest,代表着一个即将发送出去的RIL请求,它里面包含了Request请求号、序列号(自0开始累加)和保存请求结果的Message。
/**
(3).RILReceiver实现了Runnable。因此这里消息的接收应该在重写的run方法中。该方法中先用一个外层的死循环来连接socket套接字的端点(endPoint,不太懂),但通过 s.connect(l);可能会连接不成功(原因不是很理解,之后再查吧),因此这里如果尝试不成功,会终止执行后面的代码,开始下一次循环,记录尝试次数的变量retryCount 在这里没有看到太大用处,仅是用来根据其值输出相应的日志信息,连接成功后,重置了该retryCount,并将套接字赋值给了全局的变量mSocket ,此后开始其嵌套的内层死循环。内层死循环是从socket中获取到rild的响应,通过readRilMessage(InputStream is, byte[] buffer)将回应写入到buffer缓冲区里,并返回消息的长度,之后再通过 p.unmarshall( buffer , 0, length)得到原始的字节(发送的时候进行了marshall处理),接下来就是通过 processResponse(p)进行消息的处理了,之后先设置当前radio的状态,再关闭socket,重置RILRequest的序列号,并放回RILRequest池里,清空mRequestsList ,最后再用notifyRegistrantsRilConnectionChanged通知所有的registrants(应该是监听ril的吧,具体细节不知),ril已经连接或者断开,当然这里是通知断开了。
(4).接下来看一下 processResponse(p)这里的操作。主要是对消息的处理,这里的分支是因为为了匹配定义在ril.cpp的常量值也就是AT的response的两个分类,这两个值分别是:RESPONSE_SOLICITED请求响应(对ril的请求响应,比如这里的开启数据网络)和RESPONSE_UNSOLICITED非请求响应(主动响应,主动上报的,比如网络状态,短信,来电等)。因此processSolicited (p)是对数据网络请求的回应的处理。之后调用releaseWakeLockIfDone释放唤醒锁(唤醒锁是一种机制用来表示有应用程序需要设备留在唤醒状态)。
(5).processSolicited(p)方法对响应进行处理。方法中从parcel读取数据,根据读取的serial(从Android启用GPRS流程(MTK)的(21)中加入到mRequestsList)使用findAndRemoveRequestFromList找到RILRequest实例,再根据RILRequest的request值找到相应的分支。根据在setupDataCall(Android启用GPRS流程(MTK) (20) )请求的code是RIL_REQUEST_SETUP_DATA_CALL找到该分支。该该分支中调用了responseSetupDataCall(p)方法对响应的结果进行解析,包括ip地址,网关,dns等等。如果解析发现有错误,将抛出异常。不管是否存在异常,都会将AR执行的返回结果放置到AsyncResult中,并赋值给RILRequest中的Message的obj,再通过sendToTarget()发送给调用者处理。这里的Mssage最初是在GsmDataConnection或CdmaDataConnection中的onConnect()方法中创建的,其关联的handler是StateMachine.java中的SmHandler,因此最终的消息处理在DataConnection.java中。进入到DataConnection.java,找到处理Message.what为EVENT_SETUP_DATA_CONNECTION_DONE的地方。
………..
cat libs/telephony/ril_commands.h \
| egrep “^ *{RIL_” \
| sed -re ‘s/{([^,]+),[^,]+,([^}]+).+/case \1: ret = \2(p); break;/’
//使用异常和处理的结果,及消息,新构造一个AsyncResult ,并赋值给message的obj对象,该变了obj的值,obj就包含了更多信息。
/* Saves and sets m.obj /
(6).DataConnection.java对EVENT_SETUP_DATA_CONNECTION_DONE的处理在DcActivatingState的processMessage()方法中。说明当ril的消息返回时,此时的连接状态正处在激活中。msg当中包含的obj就是在上AsyncResult. forMessage()处理之后的AsyncResult,而AsyncResult中的userObj实际上就是在GsmDataConnection/CdmaDataConnection的OnConnect()方法当中封装到Message当中的ConnectionParams。如果在RIL.java中处理AT的响应详细有异常,AsyncResult中的成员变量result将为null,如果没有异常则成员变量exception为null ,当从消息之中获取到这些消息后,调用onSetupConnectionCompleted方法对AsyncResult进行处理和分类。只有当结果为 DataCallState.SetupResult为SUCCESS时才会切换到ActiveState状态.在切换到ActiveState状态之前,先通过setEnterNotificationParams()方法将连接参数cp和failCause设置给DcActiveState状态的成员变量mConnectionParams和mFailCause,在transitionTo到Activestate后,将会在其enter()方法中调用notifyConnectCompleted()将连接成功的消息发送出去。
/**
}
(7).看看onSetupConnectionCompleted()方法都做是怎么做的处理吧。先根据成员变量exception是否为null判断。如果不为null根据exception的类型,判断是属于何种异常则关联上相应的失败原因。如果为null,则判断连接参数的tag值与当前的tag值是否一致(该值在DataConnection的DcInactiveState中的enter方法修改值并在EVENT_CONNECT发生时,放置到了ConnectionParams中),一致则说明是同一次网络开启请求的处理,否则则认为本次响应的信息是错误的。即没有异常,tag值也能匹配,并且响应的staus是正确的,说明本次开启操作正确,接下来更新使用updateLinkProperty()方法更新LinkProperties(包括HttpProxy,会调用DataCallState中的setLinkProperties()方法,将DataCallState的成员变量ifname,addresses, dnses ,gateways 等关联到LinkProperties中,ifname就是interface name对应apn创建成功之后的网络设备名),并将状态机切换到ActiveState状态。
(8).根据notifyConnectCompleted()名,明显可以知道该方法是通知网络连接完成用的。那来看看这个方法都做了些啥子东西。是怎么把消息发送出去的。
方法先从cp中取相应的Message,这个message是哪儿来的呢,回忆一下。在Android 启用GPRS流程(MTK)中,当DataConnection.java的bringUp()方法时将传递过来的参数message和apnStting封装成了ConnectionParams,所以这里判断的cp. onCompletedMsg就是传递给bringUp的那个参数Message,好吧。再回忆一下,这个message是在哪儿传给bringUp()的。实际上这个message是在CdmaDataConnectionTracker和GsmDataConnectionTracker中的setupData()方法中进行构造的。
接下来将唯一标识当前数据请求的id放置在message的arg1中,并根据记录下当前的时间戳,然后将该Message又构造成一个一个AsyncResult实例。(为什么要构造成AsyncResult来进行传递,不是很明白)发送给相应的handler进行处理。由于在构造message时是使用的GsmDataConnectionTracker.java和CdmaDataConnectionTracker.java的obtainMessage方法,而这两个Tracker继承自DataConnectionTracker而DataConnectionTracker又继承自Handler,因此该消息将在DataConnectionTracker中进行处理。
(9).DataConnectionTracker.java中的handleMessage方法中找到分支
(/frameworks/opt/telephony/src/java/com/android/internal/telephony/DataConnectionTracker.java)
看到将arg1(也就是唯一的请求标识cid)赋值给了成员变量mCidActive 。比较简单没什么说的,接下来还是看onDataSetupComplete()方法。不出意外的肯定又会分支到CdmaDataConnectionTracker和GsmDataConnectionTracker。
(10).先看CdmaDataConnectionTracker中onDataSetupComplete()方法吧
首先是将AsyncResult的uerObj成员变量取出来(CdmaDataConnectionTracker在构造EVENT_DATA_SETUP_COMPLETE时,传递的reason是字符串,而GsmDataConnectionTracker传递是ApnContext)。稍后使用DataConnectionTracker中的isDataSetupCompleteOk()对AsyncResult进行是否创建完成的判断。
由于在成功返回构造AsyncResult只使用了Message,因此这里AsyncResult的exception成员变量必定为null,接下来是通过判断CdmaDataConnectionTracker的成员变量mFailDataSetupCounter来决定数据连接的创建返回值。而mFailDataSetupCounter的值只有在接收到广播
// Used for debugging. Send the INTENT with an optional counter value with the number
// of times the setup is to fail before succeeding. If the counter isn’t passed the
// setup will fail once. Example fail two times with FailCause.SIGNAL_LOST(-3)
// adb shell am broadcast \
// -a com.android.internal.telephony.dataconnectiontracker.intent_set_fail_data_setup_counter \
// –ei fail_data_setup_counter 3 – ei fail_data_setup_fail_cause -3
protectedstaticfinalStringINTENT_SET_FAIL_DATA_SETUP_COUNTER=
时才会改变。根据该广播的注释可知它是用于调试的,用来记录接续之前建立数据失败的次数。实际上这里没什么用,所以这里通常都是返回成功的。因此将直接调用notifyDefaultData(String reason)通知网络状态改变了。
privatevoidnotifyDefaultData(String reason) {
和GsmDataConnectionTracker不同,GsmDataConnectionTracker重写了这个方法。
notifyDataConnection(reason);调用的是DataConnectionTracker.java方法,在该方法中通过PhoneBase的notifyDataConnection(string,string)把消息传递出去。
再回到onDataSetupComplete(AsyncResult ar),如果失败了,根据参数中ar携带的FailCause进行分支处理,如果FailCause是固定错误,则不会进行失败尝试(MTK这里进行了修改,cause.isPermanentFail()始终返回的为false),如果ar携带的异常类型是DataConnection.CallSetupException,则从取该异常的成员变量mRetryOverride进行重试数据建立建立
(11).回到GsmDataConnectionTracker.java的onDataSetupComplete(AsyncResult ar).由于在GsmDataConnectionTracker中的setupData()方法中进行构造Message传递的message的obj对象是ApnContext,因此这里首先从ar中取出userobj进行类型判断和强转,如果类型不匹配,将抛出异常,反之则得到一个ApnConext实例。和CdmaDataConnectionTracker一样,也是调用DataConnectionTracker的isDataSetupCompleteOk(ar)对数据连接完成进行确认的判断,若为false则需要进行相应的处理,处理之后使用trySetupData()方法对建立数据连接进行重试。如果为ture,则从apnContext中取出DataConnectionAc实例,该实例是用来在不同handler之间进行消息传递的通道,这个DataConnectionAc的设置是在setupData(ApnContext apnContext)进行的,如果该实例不存在,则存在该错误,并进行数据连接重试,若存在,则再从apnContext中取出DataConnection和apnSetting的实例,并根据apnSetting中包含的端口号,代理信息构造ProxyProperties ,再由DataConnectionAc更新到当前LinkProperties上去。最后判断一下当前的连接是不是default连接,并更新systemProperties(gsm.defaultpdpcontext.active),如果是默认连接且mPreferredApn 尚为设置,则更新mPreferredApn 的引用。最后通过notifyDefaultData(apnContext)通知当前数据连接状态;
(12).来看看GsmDataConnectionTracker中的notifyDefaultData(apnContext)做了些什么处理.和第(10)中CdmaDataConnectionTracker的notifyDefaultData(String)做的事情都差不多,更新ApnContext的状态,开启NetStatPoll,DataStallAlarm,重置重试次数,之后也是通过phoneBase的实例mPhone调用notifyDataConnection(string,string)把消息传递出去。Gsm和Cdma的分支在这里又合并到一起。
(13).PhoneBase继承自handler,实现了Phone接口。在这个方法中又调用PhoneNotifier的来传递消息,它是对所有系统范围状态改变通知的抽象。DefaultPhoneNotifier实现了phoneNotifier,这里实际上调用的DefaultPhoneNotifier的notifyDataConnection(Phone sender, String reason, String apnType, DataState state)方法.此外在getDataConnectionState(apntype)会分支到GSMPhone.java和CDMAPhone.java,返回相对应的PhoneConstants中的DataState枚举类型(这里是返回PhoneConstants.DataState.CONNECTED)
(frameworks/opt/telephony/src/java/com/android/internal/telephony/PhoneBase.java)
(frameworks/base/telephony/java/com/android/internal/telephony/PhoneConstants.java)
(frameworks/opt/telephony/src/java/com/android/internal/telephony/cdma/CDMAPhone.java)
(frameworks/opt/telephony/src/java/com/android/internal/telephony/gsm/GSMPhone.java)
在DefaultPhoneNotifier中又调用了doNotifyDataConnection()方法,接下来就看看这个方法做了什么处理
//MTK-START [mtk04070][111125][ALPS00093395]MTK modified
//MTK-END [mtk04070][111125][ALPS00093395]MTK modified
(14).doNotifyDataConnection() 根据传入的 apnType先从phone 中取出连接参数 linkProperties 和linkCapabilities( 代表链接功能的类 ),再获取包含手机状态和服务相关信息的 ServiceState实例,作为之后TelephonyRegistry和 notifyDataStateChangeCallback()的参数。之后通过ITelephonyRegistry.aidl跨进程调用到 TelephonyRegistry.java的notifyDataConnection() 方法。
(frameworks/opt/telephony/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java)
(/frameworks/base/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl)
notifyDataStateChangeCallback() 根据方法名推测是一个数据状态改变的回调
IDataStateChangedCallback 是一个接口,包含一个方法,该方法在 framework中没有找到该接口的实现,推测是内置的系统级别应用程序进行实现。
(15).TelephonyRegistry的 notifyDataConnection()方法。首先是检查是否有 notify权限( android.Manifest.permission.MODIFY_PHONE_STATE ),没有权限的话,将不会继续执行连接消息的传递。再判断是否需要对目前的连接信息进行修改,如果有进行修改,则标记 modified为true 。方法中 mRecords.events的实际上就是在NetworkController.java中注册的消息,如果这些消息存在,并且 过IPhoneStateListener的 onDataConnectionStateChanged()回调触发相应的处理,(之前进行过 LISTEN_DATA_CONNECTION_STATE 注册的都将触发,已知 NetworkController.java)。最后通过broadcastDataConnectionStateChanged () 发送网络状态改变的广播出去, ConnectivityService.java中将接收到这个广播,再继续做处理。
(frameworks/base/services/java/com/android/server/TelephonyRegistry.java)
(16)在framework 中NetworkController.java(/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java )的构造方法中调用了TelephonyManager的 listen方法进行注册。监听包括网络服务状态 (LISTEN_SERVICE_STATE), 信号强弱 (LISTEN_SIGNAL_STRENGTHS状态栏的信号强度图标 ),手机通话状态(通话,空闲,响铃 LISTEN_CALL_STATE),数据连接状态 (LISTEN_DATA_CONNECTION_STATE),以及数据连接上的数据业务方向改变 (状态栏使用它来显示相应的数据流量图标 )。
在框架中NetworkStatsService.java中也进行了TelephonyManager的listen方法进行PhoneStateListener. LISTEN_DATA_CONNECTION_STATE 注册,不过貌似应该不会触发。由于
COMBINE_SUBTYPE_ENABLED 恒为true ,这里只是提出来这个类有注册的行为。
(frameworks/base/services/java/com/android/server/net/NetworkStatsService.java)
(17).在系统内置的应用程序Settings中也调用了 TelephonyManager的listen 方法进行了 PhoneStateListener. LISTEN_DATA_CONNECTION_STATE注册( 可能还有其他应用程序进行相同操作,但目前只发现 settings,内置程序phne中 /src/com/android/phone/CallNotifier.java进行了 PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR |PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR |PhoneStateListener.LISTEN_SERVICE_STATE单未进行 LISTEN_DATA_CONNECTION_STATE 的注册)
(/packages/apps/Settings/src/com/android/settings/deviceinfo/Status.java)
(/packages/apps/Settings/src/com/android/settings/RadioInfo.java)
先来看下 Status.java
再来看 RadioInfo.java
(18.)接下来看下TelephonyManager的 listen方法实现( /frameworks/base/telephony/java/android/telephony/TelephonyManager.java ):根据相应的PhoneStateListener类型,在 TelephonyRegistry.java实现相应的listen 方法。
(19).回到TelephonyRegistry.java 来看看它的 listen方法实现
(20).当TelephonyRegistry 的notifyDataConnection()方法中触发 onDataConnectionStateChanged()时,实际上将回调到以下地方:具体都是做一些更新的操作
a.在framework 中NetworkController.java
b.在framework 中NetworkStatsService.java
c.在应用程序Setting中 Status.java中:
d.在应用程序Setting中 RadioInfo.java中:
(21).TelephonyRegistry的 notifyDataConnection()方法最后调用 broadcastDataConnectionStateChanged ()方法发送数据连接变化的广播.这里将当前的状态, apn类型,连接参数等都封装在了 action为ACTION_ANY_DATA_CONNECTION_STATE_CHANGED_MOBILE的intent 中,通过intent将这些内容发送出去。之后 frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/toolbar/QuickSettingsConnectionModel.java 和/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/toolbar/SimSwitchPanel.java 将接收到该广播并进行处理。
(21).在广播ACTION_ANY_DATA_CONNECTION_STATE_CHANGED_MOBILE发送之后,将被 MobileDataStateTracker中的内部类MobileDataStateReceiver和 TelephonyRegistry的mDataConnChangeReceiver 接收。TelephonyRegistry中将接收到 intent又使用action :TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED发送出去。
而在 MobileDataStateReceiver中处理则比较复杂,这里就没有不再进行细致分析了。先根据 intent中的apntype 从全局的trakerMap中取出相应的 tracker 实例,再根据PhoneConstants. STATE_KEY 取出 state值,并由此进行分支处理。在 CONNECTED 分支中, tracker调用setDetailedState() 修改apn对应的 networkinfo中的状态信息,并发送EVENT_STATE_CHANGED消息 ,ConnectionService的内部类NetworkStateTrackerHandler 将接收该消息并进行处理。
(22).回到ConnectionService.java 中来,这里果然是连接管理的最核心啊,也是反馈的终点了。
(23.)最后一步操作了,根据NetworkInfo对应状态变化执行 handleConnect(进行Connected 处理)或者 handleDisconnect(Disconnected)处理。并发出 CONNECTIVITY_ACTION 的广播,该广播是一个公共广播,应用程序或者框架中都可以进行广播的接收。消息传递给应用程序,知晓了网络的连接状况已经改变,并且可以获取到具体当前的网络状态
private void handleDisconnect(NetworkInfo info) {
………
理解了建立GPRS通信的流程再来看这篇文章就相对来说好理解了
android通信流程本身就是一个很复杂的问题,我只是以我工作过程中遇到的细节为主要线索,理一理整个过程中需要注意的地方,如有错误和不当,还望大家海涵和指正。
(1).先回过头来看看数据网络开启过程中的CdmaDataConnection和GsmDataConnection中的onConnect()方法,该方法中在调用RIL的setupDataCall()时,传入了标识为EVENT_SETUP_DATA_CONNECTION_DONE 的Message,在RIL的setupDataCall()使用该Message获取了RILRequest的实例并将该message作为RIL Parcel的第一个元素写入到其中。
RILRequest rr = RILRequest. obtain(RIL_REQUEST_SETUP_DATA_CALL, result);
该obtain方法作用是从池中检索一个新的RILRequest实例,第一个参数是定义在RILConstants中以RIL_REQUEST_打头的整型值,第二个参数是操作完成后要发送的东西。由此看来之前标识EVENT_SETUP_DATA_CONNECTION_DONE 的Message会在执行完后将发送出去。RILRequest,代表着一个即将发送出去的RIL请求,它里面包含了Request请求号、序列号(自0开始累加)和保存请求结果的Message。
/**
* Retrieves a new RILRequest instance from the pool. * * @param request RIL_REQUEST_* * @param result sent when operation completes * @return a RILRequest instance from the pool. */ 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(); } synchronized(sSerialMonitor ) { rr. mSerial = sNextSerial++; } rr. mRequest = request; rr. mResult = result; rr. mp = Parcel.obtain(); //这里要求message不能为空,并且已经关联了相应的handler,看来在执行完操作之后发送的消息将由此handler接收并处理
if (result != null && result.getTarget() == null) { throw new NullPointerException("Message target must not be null"); }
// first elements in any RIL Parcel rr. mp.writeInt(request); rr. mp.writeInt(rr.mSerial ); return rr; }
(2).当RILSender发送一个RIL请求后(即Android启动GPRS流程(MTK)中(21)的send方法),rild收到请求后会进行分发,发送AT命令,若AT命令没有得到响应回复(分为2种,请求回应和主动上报),rild的分发线程被阻塞,java部分的RIL请求送出去后将得不到处理。当RIL请求得到正常处理时,RILReciver所在的线程(在RIL的构造方法中初始化)将接收到回送的response消息,并进行解析。 //***** Instance Variables //定义在RIL类中的成员变量 LocalSocket mSocket; HandlerThread mSenderThread;/ RILSender mSender; Thread mReceiverThread; RILReceiver mReceiver; ------------------------------------------------------------------ public RIL(Context context, int preferredNetworkType, int cdmaSubscription) { super(context); if (RILJ_LOGD) { riljLog("RIL(context, preferredNetworkType=" + preferredNetworkType + " cdmaSubscription=" + cdmaSubscription + ")"); } mCdmaSubscription = cdmaSubscription; mPreferredNetworkType = preferredNetworkType; mPhoneType = RILConstants.NO_PHONE; PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG); mWakeLock.setReferenceCounted(false); mWakeLockTimeout = SystemProperties.getInt(TelephonyProperties.PROPERTY_WAKE_LOCK_TIMEOUT, DEFAULT_WAKE_LOCK_TIMEOUT); mRequestMessagesPending = 0; mRequestMessagesWaiting = 0; //初始化SenderThread,RILSender mSenderThread = new HandlerThread("RILSender"); mSenderThread.start(); Looper looper = mSenderThread.getLooper(); mSender = new RILSender(looper); ConnectivityManager cm = (ConnectivityManager)context.getSystemService( Context.CONNECTIVITY_SERVICE); if (cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) { riljLog("Not starting RILReceiver: wifi-only"); } else { riljLog("Starting RILReceiver"); //初始化RILReceiver和mReceiverThread mReceiver = new RILReceiver(); mReceiverThread = new Thread(mReceiver, "RILReceiver"); mReceiverThread.start(); IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_SCREEN_ON); filter.addAction(Intent.ACTION_SCREEN_OFF); context.registerReceiver(mIntentReceiver, filter); } }
(3).RILReceiver实现了Runnable。因此这里消息的接收应该在重写的run方法中。该方法中先用一个外层的死循环来连接socket套接字的端点(endPoint,不太懂),但通过 s.connect(l);可能会连接不成功(原因不是很理解,之后再查吧),因此这里如果尝试不成功,会终止执行后面的代码,开始下一次循环,记录尝试次数的变量retryCount 在这里没有看到太大用处,仅是用来根据其值输出相应的日志信息,连接成功后,重置了该retryCount,并将套接字赋值给了全局的变量mSocket ,此后开始其嵌套的内层死循环。内层死循环是从socket中获取到rild的响应,通过readRilMessage(InputStream is, byte[] buffer)将回应写入到buffer缓冲区里,并返回消息的长度,之后再通过 p.unmarshall( buffer , 0, length)得到原始的字节(发送的时候进行了marshall处理),接下来就是通过 processResponse(p)进行消息的处理了,之后先设置当前radio的状态,再关闭socket,重置RILRequest的序列号,并放回RILRequest池里,清空mRequestsList ,最后再用notifyRegistrantsRilConnectionChanged通知所有的registrants(应该是监听ril的吧,具体细节不知),ril已经连接或者断开,当然这里是通知断开了。
public void run() { int retryCount = 0; String socketRil = getRilSocketName( mySimId); try { for (;;) {//外层死循环,用来处理socket的连接 LocalSocket s = null; LocalSocketAddress l; socketRil = getRilSocketName( mySimId); .......... try { s = new LocalSocket(); l = new LocalSocketAddress(socketRil, LocalSocketAddress.Namespace. RESERVED); s.connect(l); } catch (IOException ex){ try { if (s != null) { s.close(); } } catch (IOException ex2) { //ignore failure to close after failure to connect } // don't print an error message after the the first time // or after the 8th time //官方源码这里值是8,注释也可以看出来,这里MTK做了修改,将值增大到16 if (retryCount == 16) { Log. e (LOG_TAG, "Couldn't find '" + socketRil + "' socket after " + retryCount + " times, continuing to retry silently" ); } else if (retryCount > 0 && retryCount < 16) { Log. i (LOG_TAG, "Couldn't find '" + socketRil + "' socket; retrying after timeout" ); } try { Thread. sleep(SOCKET_OPEN_RETRY_MILLIS); } catch (InterruptedException er) { } retryCount++; continue; } retryCount = 0; mSocket = s; Log. i(LOG_TAG, "Connected to '" + socketRil + "' socket" ); int length = 0; try { InputStream is = mSocket.getInputStream(); for (;;) { //内层死循环用来从输入流中读取数据 Parcel p; //readRilMessage是把以 little-endian 存储的数据还原到本来的样子 //以 little-endian 存储时,数据低位存储在内存低地址,数据高位存储在内存高地址; //read(buffer, offset, remaining); 读入 remaining 长度的流数据; //JVM 用 little-endian 存储 int 型的 messageLength ,所以得用位操作转换一下 length = readRilMessage(is, buffer); if (length < 0) { // End-of-stream reached break; } p = Parcel. obtain(); p.unmarshall( buffer, 0, length);//返回原始字节数据 p.setDataPosition(0); //Log.v(LOG_TAG, "Read packet: " + length + " bytes"); processResponse(p);//处理回应 p.recycle(); } } catch (java.io.IOException ex) { Log. i(LOG_TAG, "'" + socketRil + "' socket closed" , ex); } catch (Throwable tr) { Log. e(LOG_TAG, "Uncaught exception read length=" + length + "Exception:" + tr.toString()); } Log. i(LOG_TAG, "Disconnected from '" + socketRil + "' socket"); setRadioState (RadioState. RADIO_UNAVAILABLE);//存储新的radio状态为无效状态并发送通知 try { mSocket.close(); } catch (IOException ex) { } mSocket = null; RILRequest. resetSerial();//重置序列号 // Clear request list on close synchronized (mRequestsList ) { for (int i = 0, sz = mRequestsList.size() ; i < sz ; i++) { RILRequest rr = mRequestsList.get(i); rr.onError( RADIO_NOT_AVAILABLE, null ); rr.release();//将RILRequest放回池中 } mRequestsList.clear(); //清理请求列表 } }} catch (Throwable tr) { Log. e(LOG_TAG, "Uncaught exception", tr); } //MTK-END [mtk04070][111121][ALPS00093395]Refined for supporting Gemini /* We're disconnected so we don't know the ril version */ notifyRegistrantsRilConnectionChanged(-1);//通知所有的Registrants,ril的连接状态改变 }
(4).接下来看一下 processResponse(p)这里的操作。主要是对消息的处理,这里的分支是因为为了匹配定义在ril.cpp的常量值也就是AT的response的两个分类,这两个值分别是:RESPONSE_SOLICITED请求响应(对ril的请求响应,比如这里的开启数据网络)和RESPONSE_UNSOLICITED非请求响应(主动响应,主动上报的,比如网络状态,短信,来电等)。因此processSolicited (p)是对数据网络请求的回应的处理。之后调用releaseWakeLockIfDone释放唤醒锁(唤醒锁是一种机制用来表示有应用程序需要设备留在唤醒状态)。
private void processResponse (Parcel p) { int type; type = p.readInt(); //MTK修改开始 /* Solve [ALPS00308613]Receive incoming VT call causes EE, mtk04070, 20120628 */ if (mIsFirstResponse && ((type == RESPONSE_UNSOLICITED) || (type == RESPONSE_SOLICITED))) { if (FeatureOption.MTK_VT3G324M_SUPPORT == false) { Log. d(LOG_TAG, "FeatureOption.MTK_VT3G324M_SUPPORT == false" ); disableVTCapability(); } mIsFirstResponse = false; } //MTK修改结束 if (type == RESPONSE_UNSOLICITED) { processUnsolicited (p); } else if (type == RESPONSE_SOLICITED) { processSolicited (p); } releaseWakeLockIfDone(); }
(5).processSolicited(p)方法对响应进行处理。方法中从parcel读取数据,根据读取的serial(从Android启用GPRS流程(MTK)的(21)中加入到mRequestsList)使用findAndRemoveRequestFromList找到RILRequest实例,再根据RILRequest的request值找到相应的分支。根据在setupDataCall(Android启用GPRS流程(MTK) (20) )请求的code是RIL_REQUEST_SETUP_DATA_CALL找到该分支。该该分支中调用了responseSetupDataCall(p)方法对响应的结果进行解析,包括ip地址,网关,dns等等。如果解析发现有错误,将抛出异常。不管是否存在异常,都会将AR执行的返回结果放置到AsyncResult中,并赋值给RILRequest中的Message的obj,再通过sendToTarget()发送给调用者处理。这里的Mssage最初是在GsmDataConnection或CdmaDataConnection中的onConnect()方法中创建的,其关联的handler是StateMachine.java中的SmHandler,因此最终的消息处理在DataConnection.java中。进入到DataConnection.java,找到处理Message.what为EVENT_SETUP_DATA_CONNECTION_DONE的地方。
private void processSolicited (Parcel p) { int serial, error; boolean found = false; serial = p.readInt(); error = p.readInt(); RILRequest rr; rr = findAndRemoveRequestFromList(serial); if (rr == null) { Log. w(LOG_TAG, "Unexpected solicited response! sn: " + serial + " error: " + error); return; }
………..
if (error == 0 || p.dataAvail() > 0) { // either command succeeds or command fails but with data payload try {switch (rr.mRequest) { /*
cat libs/telephony/ril_commands.h \
| egrep “^ *{RIL_” \
| sed -re ‘s/{([^,]+),[^,]+,([^}]+).+/case \1: ret = \2(p); break;/’
*/ //接下来非常多的RIL请求处理,目测有几十种(这里省略部分) case RIL_REQUEST_GET_SIM_STATUS : ret = responseIccCardStatus(p); break; ......... case RIL_REQUEST_SEND_SMS : ret = responseSMS(p); break; case RIL_REQUEST_SEND_SMS_EXPECT_MORE : ret = responseSMS(p); break; case RIL_REQUEST_SETUP_DATA_CALL : ret = responseSetupDataCall(p); break; ..... case RIL_REQUEST_QUERY_MODEM_TYPE : ret = responseInts(p); break; default: throw new RuntimeException("Unrecognized solicited response: " + rr. mRequest); //break; }} catch (Throwable tr) { // Exceptions here usually mean invalid RIL responses //解析发现RILResponse存在错误,就会抛出异常 Log. w(LOG_TAG, rr.serialString() + "< " + requestToString(rr.mRequest) + " exception, possible invalid RIL response" , tr); if (rr.mResult != null) {//只要message不为空,仍然将其回送到调用者并由其进行处理 AsyncResult. forMessage(rr.mResult, null, tr);//使用新构造一个AsyncResult ,并赋值给message的obj对象 rr. mResult.sendToTarget(); } rr.release();//将RILRequest放回池中 return; } } if (error != 0) { rr.onError(error, ret); rr.release(); return; } if (RILJ_LOGD ) riljLog(rr.serialString() + "< " + requestToString(rr.mRequest) + " " + retToString(rr.mRequest , ret)); if (rr.mResult != null) { //解析正常,并且message存在,将AT执行的返回结果放到AsyncResult中,并赋值rr. mResult的obj,再由sendToTarget()回送到调用者并由其进行处理 AsyncResult. forMessage(rr.mResult, ret, null);//赋值到rr.mResult的obj对象 rr. mResult.sendToTarget(); } rr.release(); }
//使用异常和处理的结果,及消息,新构造一个AsyncResult ,并赋值给message的obj对象,该变了obj的值,obj就包含了更多信息。
/* Saves and sets m.obj /
public static AsyncResult forMessage (Message m, Object r, Throwable ex) { AsyncResult ret; //此时m.obj是 ret = new AsyncResult (m.obj , r, ex); m. obj = ret; return ret; }
(6).DataConnection.java对EVENT_SETUP_DATA_CONNECTION_DONE的处理在DcActivatingState的processMessage()方法中。说明当ril的消息返回时,此时的连接状态正处在激活中。msg当中包含的obj就是在上AsyncResult. forMessage()处理之后的AsyncResult,而AsyncResult中的userObj实际上就是在GsmDataConnection/CdmaDataConnection的OnConnect()方法当中封装到Message当中的ConnectionParams。如果在RIL.java中处理AT的响应详细有异常,AsyncResult中的成员变量result将为null,如果没有异常则成员变量exception为null ,当从消息之中获取到这些消息后,调用onSetupConnectionCompleted方法对AsyncResult进行处理和分类。只有当结果为 DataCallState.SetupResult为SUCCESS时才会切换到ActiveState状态.在切换到ActiveState状态之前,先通过setEnterNotificationParams()方法将连接参数cp和failCause设置给DcActiveState状态的成员变量mConnectionParams和mFailCause,在transitionTo到Activestate后,将会在其enter()方法中调用notifyConnectCompleted()将连接成功的消息发送出去。
/**
* The state machine is activating a connection. */ private class DcActivatingState extends State { @Override public boolean processMessage(Message msg) { boolean retVal; AsyncResult ar; ConnectionParams cp; ........ case EVENT_SETUP_DATA_CONNECTION_DONE : if (DBG ) log("DcActivatingState msg.what=EVENT_SETUP_DATA_CONNECTION_DONE"); ar = (AsyncResult) msg. obj; // cp = (ConnectionParams) ar. userObj; DataCallState.SetupResult result = onSetupConnectionCompleted(ar); if (DBG ) log("DcActivatingState onSetupConnectionCompleted result=" + result); switch (result) { case SUCCESS : // All is well mActiveState.setEnterNotificationParams(cp, FailCause.NONE); transitionTo( mActiveState); break; case ERR_BadCommand ://指令错误 // Vendor ril rejected the command and didn't connect. // Transition to inactive but send notifications after // we've entered the mInactive state. mInactiveState.setEnterNotificationParams(cp, result.mFailCause, -1); transitionTo( mInactiveState); break; case ERR_UnacceptableParameter : // The addresses given from the RIL are bad tearDownData(cp); transitionTo( mDisconnectingErrorCreatingConnection ); break; case ERR_GetLastErrorFromRil : //获取到了上一次RIL请求的消息,然后会切换到mInactiveState状态去 // Request failed and this is an old RIL phone.mCM .getLastDataCallFailCause( obtainMessage( EVENT_GET_LAST_FAIL_DONE, cp)); break; case ERR_RilError ://ril层存在错误 // Request failed and mFailCause has the reason mInactiveState.setEnterNotificationParams(cp, result.mFailCause, getSuggestedRetryTime(ar)); transitionTo( mInactiveState); break; case ERR_Stale : // Request is stale, ignore. break; default: throw new RuntimeException("Unknown SetupResult, should not happen"); } retVal = HANDLED; break; ........
}
(7).看看onSetupConnectionCompleted()方法都做是怎么做的处理吧。先根据成员变量exception是否为null判断。如果不为null根据exception的类型,判断是属于何种异常则关联上相应的失败原因。如果为null,则判断连接参数的tag值与当前的tag值是否一致(该值在DataConnection的DcInactiveState中的enter方法修改值并在EVENT_CONNECT发生时,放置到了ConnectionParams中),一致则说明是同一次网络开启请求的处理,否则则认为本次响应的信息是错误的。即没有异常,tag值也能匹配,并且响应的staus是正确的,说明本次开启操作正确,接下来更新使用updateLinkProperty()方法更新LinkProperties(包括HttpProxy,会调用DataCallState中的setLinkProperties()方法,将DataCallState的成员变量ifname,addresses, dnses ,gateways 等关联到LinkProperties中,ifname就是interface name对应apn创建成功之后的网络设备名),并将状态机切换到ActiveState状态。
private DataCallState.SetupResult onSetupConnectionCompleted (AsyncResult ar) { DataCallState response = (DataCallState) ar.result; ConnectionParams cp = (ConnectionParams) ar.userObj; DataCallState.SetupResult result; if(ar.exception!=null) { if(DBG) { log("onSetupConnectionCompleted failed, ar.exception="+ ar.exception+ " response="+ response); } if(ar.exceptioninstanceofCommandException && ((CommandException) (ar.exception)).getCommandError() == CommandException.Error.RADIO_NOT_AVAILABLE) { result = DataCallState.SetupResult.ERR_BadCommand; result.mFailCause= FailCause.RADIO_NOT_AVAILABLE; }elseif((response ==null) || (response.version< 4)) { result = DataCallState.SetupResult.ERR_GetLastErrorFromRil; }else{ result = DataCallState.SetupResult.ERR_RilError; result.mFailCause= FailCause.fromInt(response.status); } }elseif(cp.tag!=mTag) {//在EVENT_CONNECT发送时,mtag赋值到cp的tag,这里进行匹配判断,确定是否是同一次操作 if(DBG) { log("BUG: onSetupConnectionCompleted is stale cp.tag="+ cp.tag+", mtag="+mTag); } result = DataCallState.SetupResult.ERR_Stale; }elseif(response.status!= 0) { result = DataCallState.SetupResult.ERR_RilError; result.mFailCause= FailCause.fromInt(response.status); }else{// if(DBG) log("onSetupConnectionCompleted received DataCallState: "+ response); cid= response.cid; result = updateLinkProperty(response).setupResult; } return result; }
(8).根据notifyConnectCompleted()名,明显可以知道该方法是通知网络连接完成用的。那来看看这个方法都做了些啥子东西。是怎么把消息发送出去的。
private void notifyConnectCompleted(ConnectionParams cp, FailCause cause) { Log. e("YKB","notifyConnectCompleted-->ConnectionParams "+cp.apn.toString()+" msg:"+ cp.onCompletedMsg.toString()); Message connectionCompletedMsg = cp.onCompletedMsg; if(connectionCompletedMsg==null) { return; } longtimeStamp = System.currentTimeMillis(); //cid是上面第(7)点从response中取出的成员变量cid ;根据DataCallState注释说是在ril.h中的, //查到源码目 录/hardware/ril/include/telephony/ril.h, //找到cid的注释为:Context ID, uniquely identifies this call connectionCompletedMsg.arg1=cid; if(cause == FailCause.NONE) { createTime= timeStamp; AsyncResult. forMessage(connectionCompletedMsg); }else{ lastFailCause= cause; lastFailTime= timeStamp; AsyncResult. forMessage(connectionCompletedMsg, cause, newCallSetupException(mRetryOverride)); } if(DBG) log("notifyConnectionCompleted at "+ timeStamp +" cause="+ cause); connectionCompletedMsg.sendToTarget(); }
方法先从cp中取相应的Message,这个message是哪儿来的呢,回忆一下。在Android 启用GPRS流程(MTK)中,当DataConnection.java的bringUp()方法时将传递过来的参数message和apnStting封装成了ConnectionParams,所以这里判断的cp. onCompletedMsg就是传递给bringUp的那个参数Message,好吧。再回忆一下,这个message是在哪儿传给bringUp()的。实际上这个message是在CdmaDataConnectionTracker和GsmDataConnectionTracker中的setupData()方法中进行构造的。
Message msg = obtainMessage(); msg.what= DctConstants.EVENT_DATA_SETUP_COMPLETE; msg.obj= reason; conn. bringUp(msg,mActiveApn) ;
接下来将唯一标识当前数据请求的id放置在message的arg1中,并根据记录下当前的时间戳,然后将该Message又构造成一个一个AsyncResult实例。(为什么要构造成AsyncResult来进行传递,不是很明白)发送给相应的handler进行处理。由于在构造message时是使用的GsmDataConnectionTracker.java和CdmaDataConnectionTracker.java的obtainMessage方法,而这两个Tracker继承自DataConnectionTracker而DataConnectionTracker又继承自Handler,因此该消息将在DataConnectionTracker中进行处理。
(9).DataConnectionTracker.java中的handleMessage方法中找到分支
(/frameworks/opt/telephony/src/java/com/android/internal/telephony/DataConnectionTracker.java)
case DctConstants.EVENT_DATA_SETUP_COMPLETE: mCidActive= msg.arg1; onDataSetupComplete((AsyncResult) msg.obj); break;
看到将arg1(也就是唯一的请求标识cid)赋值给了成员变量mCidActive 。比较简单没什么说的,接下来还是看onDataSetupComplete()方法。不出意外的肯定又会分支到CdmaDataConnectionTracker和GsmDataConnectionTracker。
(10).先看CdmaDataConnectionTracker中onDataSetupComplete()方法吧
protected void onDataSetupComplete(AsyncResult ar) { String reason =null; if(ar.userObjinstanceofString) { reason = (String) ar.userObj; } if(isDataSetupCompleteOk(ar)) { // Everything is setup notifyDefaultData(reason); }else{ FailCause cause = (FailCause) (ar.result); if(DBG) log("Data Connection setup failed "+ cause); // No try for permanent failure if(cause.isPermanentFail()) { notifyNoData(cause); return; } intretryOverride = -1; if(ar.exceptioninstanceofDataConnection.CallSetupException) { retryOverride = ((DataConnection.CallSetupException)ar.exception).getRetryOverride(); } if(retryOverride == RILConstants.MAX_INT) { if(DBG) log("No retry is suggested."); }else{ startDelayedRetry(cause, reason, retryOverride); } } }
首先是将AsyncResult的uerObj成员变量取出来(CdmaDataConnectionTracker在构造EVENT_DATA_SETUP_COMPLETE时,传递的reason是字符串,而GsmDataConnectionTracker传递是ApnContext)。稍后使用DataConnectionTracker中的isDataSetupCompleteOk()对AsyncResult进行是否创建完成的判断。
protected boolean isDataSetupCompleteOk(AsyncResult ar) { if(ar.exception!=null) { if(DBG) log("isDataSetupCompleteOk return false, ar.result="+ ar.result); returnfalse; } if(mFailDataSetupCounter<= 0) { if(DBG) log("isDataSetupCompleteOk return true"); returntrue; } ar.result=mFailDataSetupFailCause; if(DBG) { log("isDataSetupCompleteOk return false"+ " mFailDataSetupCounter="+mFailDataSetupCounter+ " mFailDataSetupFailCause="+mFailDataSetupFailCause); } mFailDataSetupCounter-= 1; returnfalse; }
由于在成功返回构造AsyncResult只使用了Message,因此这里AsyncResult的exception成员变量必定为null,接下来是通过判断CdmaDataConnectionTracker的成员变量mFailDataSetupCounter来决定数据连接的创建返回值。而mFailDataSetupCounter的值只有在接收到广播
// Used for debugging. Send the INTENT with an optional counter value with the number
// of times the setup is to fail before succeeding. If the counter isn’t passed the
// setup will fail once. Example fail two times with FailCause.SIGNAL_LOST(-3)
// adb shell am broadcast \
// -a com.android.internal.telephony.dataconnectiontracker.intent_set_fail_data_setup_counter \
// –ei fail_data_setup_counter 3 – ei fail_data_setup_fail_cause -3
protectedstaticfinalStringINTENT_SET_FAIL_DATA_SETUP_COUNTER=
"com.android.internal.telephony.dataconnectiontracker. intent_set_fail_data_setup_counter";
时才会改变。根据该广播的注释可知它是用于调试的,用来记录接续之前建立数据失败的次数。实际上这里没什么用,所以这里通常都是返回成功的。因此将直接调用notifyDefaultData(String reason)通知网络状态改变了。
privatevoidnotifyDefaultData(String reason) {
setState(DctConstants.State.CONNECTED);//修改状态,在setState中会将CdmaDataConnectionTracker成员变量mState标记为Connected notifyDataConnection(reason);//会调用到DataConnectionTracker.java中,该方法用来发送通知-所有活动的apn当前数据连接状态。
和GsmDataConnectionTracker不同,GsmDataConnectionTracker重写了这个方法。
startNetStatPoll();//开始NetStat投票(作用不明确,暂时未理解) startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);//启动数据失速警报(大概是在指定的一个时间后发出一个广播INTENT_DATA_STALL_ALARM 这个指定的时间从Settings.Global取出) mDataConnections.get(0).resetRetryCount();//重置尝试次数为0 }
notifyDataConnection(reason);调用的是DataConnectionTracker.java方法,在该方法中通过PhoneBase的notifyDataConnection(string,string)把消息传递出去。
protected void notifyDataConnection(String reason) { for(intid = 0; id < DctConstants.APN_NUM_TYPES; id++) { // Only active apns' state changed if(dataEnabled[id] &&mActiveApn!=null &&mActiveApn.canHandleType(apnIdToType(id))) { mPhone.notifyDataConnection(reason, apnIdToType(id)); } } notifyOffApnsOfAvailability(reason); }
再回到onDataSetupComplete(AsyncResult ar),如果失败了,根据参数中ar携带的FailCause进行分支处理,如果FailCause是固定错误,则不会进行失败尝试(MTK这里进行了修改,cause.isPermanentFail()始终返回的为false),如果ar携带的异常类型是DataConnection.CallSetupException,则从取该异常的成员变量mRetryOverride进行重试数据建立建立
(11).回到GsmDataConnectionTracker.java的onDataSetupComplete(AsyncResult ar).由于在GsmDataConnectionTracker中的setupData()方法中进行构造Message传递的message的obj对象是ApnContext,因此这里首先从ar中取出userobj进行类型判断和强转,如果类型不匹配,将抛出异常,反之则得到一个ApnConext实例。和CdmaDataConnectionTracker一样,也是调用DataConnectionTracker的isDataSetupCompleteOk(ar)对数据连接完成进行确认的判断,若为false则需要进行相应的处理,处理之后使用trySetupData()方法对建立数据连接进行重试。如果为ture,则从apnContext中取出DataConnectionAc实例,该实例是用来在不同handler之间进行消息传递的通道,这个DataConnectionAc的设置是在setupData(ApnContext apnContext)进行的,如果该实例不存在,则存在该错误,并进行数据连接重试,若存在,则再从apnContext中取出DataConnection和apnSetting的实例,并根据apnSetting中包含的端口号,代理信息构造ProxyProperties ,再由DataConnectionAc更新到当前LinkProperties上去。最后判断一下当前的连接是不是default连接,并更新systemProperties(gsm.defaultpdpcontext.active),如果是默认连接且mPreferredApn 尚为设置,则更新mPreferredApn 的引用。最后通过notifyDefaultData(apnContext)通知当前数据连接状态;
@Override protected void onDataSetupComplete(AsyncResult ar) { DataConnection.FailCause cause = DataConnection.FailCause.UNKNOWN;//新构造的unkonw booleanhandleError =false; ApnContext apnContext =null; if(ar.userObjinstanceofApnContext){//obj的类型判断 apnContext = (ApnContext)ar.userObj; }else{ thrownewRuntimeException("onDataSetupComplete: No apnContext"); } if(isDataSetupCompleteOk(ar)) { //AsyncChannel to a DataConnection(数据连接的通信通道),DataConnectionAc 是为了让GsmDataConnectionTracker所在的 //handler和DataConnection所在的Handler进行通信 DataConnectionAc dcac = apnContext.getDataConnectionAc(); ........ if(dcac ==null) {//说明存在错误。 log("onDataSetupComplete: no connection to DC, handle as error"); cause = DataConnection.FailCause.CONNECTION_TO_DATACONNECTIONAC_BROKEN; handleError =true;//更新标志位,表示需要处理错误,以便重新尝试 }else{ DataConnection dc = apnContext.getDataConnection(); ApnSetting apn = apnContext.getApnSetting(); if(DBG) { log("onDataSetupComplete: success apn="+ (apn ==null?"unknown": apn.apn)); } //获取端口号,代理信息,若存在就关联到LinkProperties上去 if(apn !=null&& apn.proxy!=null&& apn.proxy.length() != 0) { try{ String port = apn.port; if(TextUtils.isEmpty(port)) port ="8080"; ProxyProperties proxy =newProxyProperties(apn.proxy, Integer. parseInt(port),null); dcac.setLinkPropertiesHttpProxySync(proxy); }catch(NumberFormatException e) { loge("onDataSetupComplete: NumberFormatException making ProxyProperties ("+ apn.port+"): "+ e); } } // everything is setup if(TextUtils.equals(apnContext.getApnType(),PhoneConstants.APN_TYPE_DEFAULT)) { SystemProperties. set("gsm.defaultpdpcontext.active","true"); if(canSetPreferApn&&mPreferredApn==null) { if(DBG) log("onDataSetupComplete: PREFERED APN is null"); mPreferredApn= apn; if(mPreferredApn!=null) { setPreferredApn(mPreferredApn.id); } } }else{ SystemProperties. set("gsm.defaultpdpcontext.active","false"); } mTetheringExt.onDataSetupComplete(apnContext); // Notify call start again if call is not IDLE and not concurrent //如果当前gsm电话状态不是空闲,并且语音通话和数据网络不支持并发,那么就要再次通知通话开始了 if(((GsmCallTracker)mGsmPhone.getCallTracker()).state!= PhoneConstants.State.IDLE&& !mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) { if(DBG) log("onDataSetupComplete: In 2G phone call, notify data REASON_VOICE_CALL_STARTED"); notifyDataConnection(Phone.REASON_VOICE_CALL_STARTED); } notifyDefaultData(apnContext); /// M: SCRI and Fast Dormancy Feature @{ //MTK-START [mtk04070][111205][ALPS00093395]Add for SCRI /* Add by MTK03594 for SCRI feature */ startScriPoll(); //MTK-END [mtk04070][111205][ALPS00093395]Add for SCRI /// @} } //isDataSetupCompleteOk(ar)为false }else{ cause = (DataConnection.FailCause) (ar.result); if(DBG) { ApnSetting apn = apnContext.getApnSetting(); log(String. format("onDataSetupComplete: error apn=%s cause=%s", (apn ==null?"unknown": apn.apn), cause)); } if(cause.isEventLoggable()) { // Log this failure to the Event Logs. intcid = getCellLocationId(); EventLog. writeEvent(EventLogTags .PDP_SETUP_FAIL, cause.ordinal(), cid, TelephonyManager. getDefault().getNetworkType()); } // Count permanent failures and remove the APN we just tried if(cause.isPermanentFail()) apnContext.decWaitingApnsPermFailCount(); if(cause == DataConnection.FailCause.GMM_ERROR&& mPhone.getServiceStateTracker().getCurrentDataConnectionState() != ServiceState.STATE_IN_SERVICE) { // stop retry for GMM_ERROR and let GPRS attach event to trigger如果是GMM_ERROR停止重试,并且触发GPRS附加事件 //更新ApnConext中的成员变量mWaitingApns和mWaitingApnsPermanentFailureCountDown(此时mWaitingApns的size为0) //mWaitingApnsPermanentFailureCountDown设置为0,而0表示mWaitingApns中的所有的apn存在永久性错误 apnContext.setWaitingApns(newArrayList<ApnSetting>()); log("onDataSetupComplete: GMM_ERROR, wait for GPRS attach to retry."); }elseif(mGsmDCTExt.needDelayedRetry(cause.getErrorCode())) {//根据FailCause中的errorcode判断是否需要重试 log("onDataSetupComplete: need delayed retry"); intretryCount = apnContext.getRetryCount(); //配置一个简单的线性序列的时间,加上一个随机值 apnContext.getDataConnection().configureRetry(2, 45000, 0);//重试参数(最大重试次数,延迟时间,随机值介于0和第二个参数之间) apnContext.getDataConnection().setRetryCount(retryCount); apnContext.removeWaitingApn(apnContext.getApnSetting());//移除所以出于waiting状态的apn } if(DBG) { log(String. format("onDataSetupComplete: WaitingApns.size=%d"+ " WaitingApnsPermFailureCountDown=%d", apnContext.getWaitingApns().size(), apnContext.getWaitingApnsPermFailCount())); } handleError =true; } //处理错误 if(handleError) { // See if there are more APN's to try if(apnContext.getWaitingApns().isEmpty()) { if(apnContext.getWaitingApnsPermFailCount() == 0) { if(DBG) { log("onDataSetupComplete: All APN's had permanent failures, stop retrying"); } apnContext.setState(DctConstants.State.FAILED); mPhone.notifyDataConnection(Phone.REASON_APN_FAILED, apnContext.getApnType()); apnContext.setDataConnection(null);//清理DataConnection,在trySetupData将重新关联新的实例 apnContext.setDataConnectionAc(null);//清理DataConnectionAc,在trySetupData将重新关联新的实例 // M: try to enable apn which is in waiting list if(apnContext.getApnType() == PhoneConstants.APN_TYPE_MMS) { enableWaitingApn(); } if(PhoneFactory.isDualTalkMode()) { if(apnContext.getApnType() != PhoneConstants.APN_TYPE_DEFAULT&&mWaitingApnList.isEmpty()) { // try to restore default trySetupData(Phone.REASON_DATA_ENABLED, PhoneConstants.APN_TYPE_DEFAULT); } } }else{ if(DBG) log("onDataSetupComplete: Not all permanent failures, retry"); // check to see if retry should be overridden for this failure. intretryOverride = -1; if(ar.exceptioninstanceofDataConnection.CallSetupException) { retryOverride = ((DataConnection.CallSetupException)ar.exception).getRetryOverride(); } if(retryOverride == RILConstants.MAX_INT) { if(DBG) log("No retry is suggested."); }else{ startDelayedRetry(cause, apnContext, retryOverride); } } //handleError为false }else{ if(DBG) log("onDataSetupComplete: Try next APN"); apnContext.setState(DctConstants.State.SCANNING); // Wait a bit before trying the next APN, so that // we're not tying up the RIL command channel startAlarmForReconnect(APN_DELAY_MILLIS, apnContext); } } }
(12).来看看GsmDataConnectionTracker中的notifyDefaultData(apnContext)做了些什么处理.和第(10)中CdmaDataConnectionTracker的notifyDefaultData(String)做的事情都差不多,更新ApnContext的状态,开启NetStatPoll,DataStallAlarm,重置重试次数,之后也是通过phoneBase的实例mPhone调用notifyDataConnection(string,string)把消息传递出去。Gsm和Cdma的分支在这里又合并到一起。
private void notifyDefaultData(ApnContext apnContext) { // M: If context is disabled and state is DISCONNECTING, // should not change the state to confuse the following enableApnType() which returns PhoneConstants.APN_ALREADY_ACTIVE as CONNECTED if(apnContext.getState() != DctConstants.State.DISCONNECTING) { apnContext.setState(DctConstants.State.CONNECTED); } // setState(DctConstants.State.CONNECTED); mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType()); startNetStatPoll(); startDataStallAlarm(DATA_STALL_NOT_SUSPECTED); // reset reconnect timer apnContext.setRetryCount(0); }
(13).PhoneBase继承自handler,实现了Phone接口。在这个方法中又调用PhoneNotifier的来传递消息,它是对所有系统范围状态改变通知的抽象。DefaultPhoneNotifier实现了phoneNotifier,这里实际上调用的DefaultPhoneNotifier的notifyDataConnection(Phone sender, String reason, String apnType, DataState state)方法.此外在getDataConnectionState(apntype)会分支到GSMPhone.java和CDMAPhone.java,返回相对应的PhoneConstants中的DataState枚举类型(这里是返回PhoneConstants.DataState.CONNECTED)
(frameworks/opt/telephony/src/java/com/android/internal/telephony/PhoneBase.java)
(frameworks/base/telephony/java/com/android/internal/telephony/PhoneConstants.java)
(frameworks/opt/telephony/src/java/com/android/internal/telephony/cdma/CDMAPhone.java)
(frameworks/opt/telephony/src/java/com/android/internal/telephony/gsm/GSMPhone.java)
public void notifyDataConnection(String reason, String apnType) { mNotifier.notifyDataConnection(this, reason, apnType, getDataConnectionState(apnType)); }
在DefaultPhoneNotifier中又调用了doNotifyDataConnection()方法,接下来就看看这个方法做了什么处理
//MTK-START [mtk04070][111125][ALPS00093395]MTK modified
public void notifyDataConnection(Phone sender, String reason, String apnType, PhoneConstants.DataState state) { doNotifyDataConnection(sender, reason, apnType, state); }
//MTK-END [mtk04070][111125][ALPS00093395]MTK modified
(14).doNotifyDataConnection() 根据传入的 apnType先从phone 中取出连接参数 linkProperties 和linkCapabilities( 代表链接功能的类 ),再获取包含手机状态和服务相关信息的 ServiceState实例,作为之后TelephonyRegistry和 notifyDataStateChangeCallback()的参数。之后通过ITelephonyRegistry.aidl跨进程调用到 TelephonyRegistry.java的notifyDataConnection() 方法。
(frameworks/opt/telephony/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java)
(/frameworks/base/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl)
private void doNotifyDataConnection(Phone sender, String reason, String apnType, PhoneConstants.DataState state) { //TODO // use apnType as the key to which connection we're talking about. // pass apnType back up to fetch particular for this one. TelephonyManager telephony = TelephonyManager. getDefault();//TelephonyManager 单列模式类,懒汉式,通过此方法获取 TelephonyManager 实例 LinkProperties linkProperties = null; LinkCapabilities linkCapabilities = null; booleanroaming =false; if(state == PhoneConstants.DataState.CONNECTED) { linkProperties = sender.getLinkProperties(apnType); linkCapabilities = sender.getLinkCapabilities(apnType); } ServiceState ss = sender.getServiceState();/ if(ss !=null) roaming = ss.getRoaming();// 获取到手机信息和服务信息类,获取漫游信息 intnetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN; if(!FeatureOption.MTK_GEMINI_SUPPORT) { // 上面通过 getDefault获取到telephony ,由于是懒汉式,所以不会为 null networkType = ((telephony!= null) ? telephony.getNetworkType() : TelephonyManager.NETWORK_TYPE_UNKNOWN ); } else{ networkType = ((telephony!= null) ? telephony.getNetworkTypeGemini (sender.getMySimId()) : TelephonyManager.NETWORK_TYPE_UNKNOWN ); } log( "doNotifyDataConnection " +"apnType="+ apnType + ",networkType="+ networkType +", state="+ state); notifyDataStateChangeCallback( state.toString(), reason, sender.getActiveApnHost(apnType), apnType, sender.isDataConnectivityPossible(apnType), mSimId); try{ // 将 PhoneConstants.DataState转换成 TelephoneManager当中定义的状态。这里是将 PhoneConstants.DataState. CONNECTED 转换为TelephonyManager.DATA_CONNECTED mRegistry.notifyDataConnection( convertDataState(state), sender.isDataConnectivityPossible(apnType),// 检查该apn数据连接是否被允许,之后会通过调用到 PhoneBase.java,再分支到CdmaDataConnectionTracker和 GsmDataConnectionTracker的isDataPossible(String apnType) 方法 reason, sender.getActiveApnHost(apnType), //返回或的apn 主机字符串 (其实是ApnSetting.apn) apnType, linkProperties, linkCapabilities, networkType, roaming); } catch(RemoteException ex) { // system process is dead } // M: Update SIM indication state for data connection state change if(senderinstanceofPhoneBase) { ((PhoneBase)sender).updateDataStateOfSimIndication(apnType, state); } }
notifyDataStateChangeCallback() 根据方法名推测是一个数据状态改变的回调
private void notifyDataStateChangeCallback(String state, String reason, String apnName, String apnType, booleanunavailable,intsimId) { Iterator<IDataStateChangedCallback> iterator = mDataStateChangedCallbacks.iterator(); while(iterator.hasNext()) { IDataStateChangedCallback callback = iterator.next(); callback.onDataStateChanged(state, reason, apnName, apnType, unavailable, simId); } }
IDataStateChangedCallback 是一个接口,包含一个方法,该方法在 framework中没有找到该接口的实现,推测是内置的系统级别应用程序进行实现。
public interface IDataStateChangedCallback { voidonDataStateChanged(String state, String reason, String apnName, String apnType, booleanunavailable,intsimId); }
(15).TelephonyRegistry的 notifyDataConnection()方法。首先是检查是否有 notify权限( android.Manifest.permission.MODIFY_PHONE_STATE ),没有权限的话,将不会继续执行连接消息的传递。再判断是否需要对目前的连接信息进行修改,如果有进行修改,则标记 modified为true 。方法中 mRecords.events的实际上就是在NetworkController.java中注册的消息,如果这些消息存在,并且 过IPhoneStateListener的 onDataConnectionStateChanged()回调触发相应的处理,(之前进行过 LISTEN_DATA_CONNECTION_STATE 注册的都将触发,已知 NetworkController.java)。最后通过broadcastDataConnectionStateChanged () 发送网络状态改变的广播出去, ConnectivityService.java中将接收到这个广播,再继续做处理。
(frameworks/base/services/java/com/android/server/TelephonyRegistry.java)
public void notifyDataConnection(intstate, booleanisDataConnectivityPossible, String reason, String apn, String apnType, LinkProperties linkProperties, LinkCapabilities linkCapabilities, intnetworkType,booleanroaming) { if(!checkNotifyPermission("notifyDataConnection()" )) { return; } synchronized(mRecords ) { // M: For synchronization of mRecords, move log into synchronization protection. if(DBG ) { Slog. i(TAG, "notifyDataConnection: state=" + state +" isDataConnectivityPossible=" + isDataConnectivityPossible + " reason='"+ reason + "' apn='"+ apn +"' apnType=" + apnType +" networkType="+ networkType + " mRecords.size()="+mRecords .size() +" mRecords="+ mRecords); } booleanmodified =false; if(state == TelephonyManager.DATA_CONNECTED) {// 数据已连接 if(!mConnectedApns .contains(apnType)) { mConnectedApns.add(apnType);//添加到连接的 apn列表中 if(mDataConnectionState != state) {//修改当前的成员变量标识连接状态 mDataConnectionState= state; modified = true; } } } else{// 如果不是连接,则移除 if(mConnectedApns .remove(apnType)) { if(mConnectedApns .isEmpty()) { mDataConnectionState= state;//连接状态修改 modified = true; } else{ // leave mDataConnectionState as is and // send out the new status for the APN in question. } } } mDataConnectionPossible= isDataConnectivityPossible; mDataConnectionReason= reason; mDataConnectionLinkProperties= linkProperties; mDataConnectionLinkCapabilities= linkCapabilities; if(mDataConnectionNetworkType != networkType) {//网络连接类型修改 mDataConnectionNetworkType= networkType; // need to tell registered listeners about the new network type modified = true; } if(modified) { if(DBG ) { Slog. d(TAG, "onDataConnectionStateChanged(" +mDataConnectionState + ", "+mDataConnectionNetworkType +")"); } for(Record r :mRecords ) { //PhoneStateListener. LISTEN_DATA_CONNECTION_STATE 侦听更改数据连接状态 if((r.events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) { try{ // 触发IPhoneStateListener的 onDataConnectionStateChanged回调 r.callback.onDataConnectionStateChanged( mDataConnectionState, mDataConnectionNetworkType); } catch(RemoteException ex) { mRemoveList.add(r.binder ); } } } handleRemoveListLocked();// mRemoveList 和 mRecords 是同步域,根据 mRemoveList的binder 移除mRecords中的 Record, } } broadcastDataConnectionStateChanged (state, isDataConnectivityPossible, reason, apn, apnType, linkProperties, linkCapabilities, roaming); }
(16)在framework 中NetworkController.java(/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java )的构造方法中调用了TelephonyManager的 listen方法进行注册。监听包括网络服务状态 (LISTEN_SERVICE_STATE), 信号强弱 (LISTEN_SIGNAL_STRENGTHS状态栏的信号强度图标 ),手机通话状态(通话,空闲,响铃 LISTEN_CALL_STATE),数据连接状态 (LISTEN_DATA_CONNECTION_STATE),以及数据连接上的数据业务方向改变 (状态栏使用它来显示相应的数据流量图标 )。
public NetworkController(Context context) { ...... ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService( Context. CONNECTIVITY_SERVICE); mHasMobileDataFeature= cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE); ....... // set up the default wifi icon, used when no radios have ever appeared updateWifiIcons(); updateWimaxIcons(); // telephony mPhone= (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE); //用的或运算将多种类型都带进去了 mPhone.listen(mPhoneStateListener , PhoneStateListener. LISTEN_SERVICE_STATE | PhoneStateListener. LISTEN_SIGNAL_STRENGTHS | PhoneStateListener. LISTEN_CALL_STATE | PhoneStateListener. LISTEN_DATA_CONNECTION_STATE | PhoneStateListener. LISTEN_DATA_ACTIVITY); ....... // broadcasts IntentFilter filter = newIntentFilter(); filter.addAction(WifiManager. RSSI_CHANGED_ACTION); filter.addAction(WifiManager. WIFI_STATE_CHANGED_ACTION); filter.addAction(WifiManager. NETWORK_STATE_CHANGED_ACTION ); filter.addAction(TelephonyIntents. ACTION_SIM_STATE_CHANGED); filter.addAction(TelephonyIntents. SPN_STRINGS_UPDATED_ACTION ); filter.addAction(ConnectivityManager. CONNECTIVITY_ACTION); filter.addAction(ConnectivityManager. INET_CONDITION_ACTION); filter.addAction(Intent. ACTION_CONFIGURATION_CHANGED ); filter.addAction(Intent. ACTION_AIRPLANE_MODE_CHANGED ); ....... }
在框架中NetworkStatsService.java中也进行了TelephonyManager的listen方法进行PhoneStateListener. LISTEN_DATA_CONNECTION_STATE 注册,不过貌似应该不会触发。由于
COMBINE_SUBTYPE_ENABLED 恒为true ,这里只是提出来这个类有注册的行为。
(frameworks/base/services/java/com/android/server/net/NetworkStatsService.java)
public void systemReady() { ......... // watch for networkType changes that aren't broadcast through // CONNECTIVITY_ACTION_IMMEDIATE above. // publicstaticfinalbooleanCOMBINE_SUBTYPE_ENABLED= true; if(!COMBINE_SUBTYPE_ENABLED ) { mTeleManager.listen(mPhoneListener ,LISTEN_DATA_CONNECTION_STATE); } registerPollAlarmLocked(); registerGlobalAlert(); }
(17).在系统内置的应用程序Settings中也调用了 TelephonyManager的listen 方法进行了 PhoneStateListener. LISTEN_DATA_CONNECTION_STATE注册( 可能还有其他应用程序进行相同操作,但目前只发现 settings,内置程序phne中 /src/com/android/phone/CallNotifier.java进行了 PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR |PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR |PhoneStateListener.LISTEN_SERVICE_STATE单未进行 LISTEN_DATA_CONNECTION_STATE 的注册)
(/packages/apps/Settings/src/com/android/settings/deviceinfo/Status.java)
(/packages/apps/Settings/src/com/android/settings/RadioInfo.java)
先来看下 Status.java
protected void onResume() { super.onResume(); ........ mTelephonyManager.listen(mPhoneStateListener , PhoneStateListener. LISTEN_DATA_CONNECTION_STATE); mTelephonyManager.listen(mSignalStrengthListener , PhoneStateListener.LISTEN_SIGNAL_STRENGTHS); mTelephonyManager.listen(mPhoneServiceListener , PhoneStateListener.LISTEN_SERVICE_STATE); ....... }
再来看 RadioInfo.java
protected void onResume() { ....... mPhoneStateReceiver.registerIntent(); mTelephonyManager.listen(mPhoneStateListener , PhoneStateListener. LISTEN_DATA_CONNECTION_STATE | PhoneStateListener.LISTEN_DATA_ACTIVITY | PhoneStateListener.LISTEN_CELL_LOCATION | PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR | PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR | PhoneStateListener.LISTEN_CELL_INFO); }
(18.)接下来看下TelephonyManager的 listen方法实现( /frameworks/base/telephony/java/android/telephony/TelephonyManager.java ):根据相应的PhoneStateListener类型,在 TelephonyRegistry.java实现相应的listen 方法。
public void listen (PhoneStateListener listener, intevents) { //MTK-START [mtk04070][111116][ALPS00093395]Support Gemini String pkgForDebug = sContext!=null ?sContext.getPackageName() : "<unknown>"; try{ // getITelephony()返回ITelephony (frameworks/base/telephony/java/com/android/internal/telephony/ITelephony.aidl) // 由应用程序 Phone中的PhoneInterfaceManager 继承ITelephony.Stub Boolean notifyNow = ( getITelephony() !=null); sRegistry.listen(pkgForDebug, listener.callback , events, notifyNow); /* Add by mtk01411 for Data related event */ if(FeatureOption.MTK_GEMINI_SUPPORT) { if(events == PhoneStateListener.LISTEN_NONE) { /* Unregister previous listened events */ mRegistry2.listen(pkgForDebug, listener.callback , events, notifyNow); } elseif(events == PhoneStateListener.LISTEN_CALL_STATE) { mRegistry2.listen(pkgForDebug, listener.callback , events, notifyNow); } else{ intdata_events = PhoneStateListener.LISTEN_NONE; if((events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) !=0 ) { data_events |= PhoneStateListener. LISTEN_DATA_CONNECTION_STATE ; } if((events & PhoneStateListener.LISTEN_DATA_ACTIVITY) !=0 ) { data_events |= PhoneStateListener. LISTEN_DATA_ACTIVITY; } if(data_events != PhoneStateListener.LISTEN_NONE) { /* For 3rd party application: */ /* This solution is only useful if only one PS can be attached for one of two sim cards */ /* If PS can be attached on both sim cards at the same time: This solution can't work */ /* => Because the same callback may recevie two same events and can't identify which event comes from which sim card */ mRegistry2.listen(pkgForDebug, listener.callback , data_events, notifyNow); } } } //MTK-END [mtk04070][111116][ALPS00093395]Support Gemini } catch(RemoteException ex) { // system process dead ex.printStackTrace(); } catch(NullPointerException ex) { // system process dead ex.printStackTrace(); } }
(19).回到TelephonyRegistry.java 来看看它的 listen方法实现
public void listen(String pkgForDebug, IPhoneStateListener callback, intevents, booleannotifyNow) { intcallerUid = UserHandle.getCallingUserId();// 多用户的处理,获取是调用的用户 id intmyUid = UserHandle.myUserId(); if(DBG ) { Slog. d(TAG, "listen: E pkg="+ pkgForDebug +" events=0x" + Integer.toHexString (events) + " myUid="+ myUid + " callerUid="+ callerUid); } if(events != 0) { /* Checks permission and throws Security exception */ checkListenerPermission(events); synchronized(mRecords ) { // register Record r = null; find_and_add: { IBinder b = callback.asBinder(); finalintN =mRecords .size(); for(int i = 0; i < N; i++) { r = mRecords.get(i); if(b == r.binder ) { breakfind_and_add; } } r = newRecord(); r. binder= b; r.callback= callback; r. pkgForDebug= pkgForDebug; r. callerUid= callerUid; mRecords.add(r);//加入到了 mRecords 中,在 notifyDataConnection中for 循环中使用 if(DBG ) Slog.i (TAG ,"listen: add new record="+ r); } intsend = events & (events ^ r.events ); r. events= events; if(notifyNow) { if((events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) { try{ r.callback.onServiceStateChanged( newServiceState(mServiceState )); } catch(RemoteException ex) { remove(r. binder); } } if((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH ) != 0) { try{ intgsmSignalStrength =mSignalStrength .getGsmSignalStrength(); r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1 : gsmSignalStrength)); } catch(RemoteException ex) { remove(r. binder); } } if((events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) { try{ r.callback.onMessageWaitingIndicatorChanged( mMessageWaiting); } catch(RemoteException ex) { remove(r. binder); } } if((events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) { try{ r.callback.onCallForwardingIndicatorChanged( mCallForwarding); } catch(RemoteException ex) { remove(r. binder); } } if(validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) { try{ r.callback.onCellLocationChanged( newBundle(mCellLocation )); } catch(RemoteException ex) { remove(r. binder); } } if((events & PhoneStateListener.LISTEN_CALL_STATE) != 0) { try{ r.callback.onCallStateChanged( mCallState,mCallIncomingNumber ); } catch(RemoteException ex) { remove(r. binder); } } if((events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) { try{ r.callback.onDataConnectionStateChanged( mDataConnectionState, mDataConnectionNetworkType); } catch(RemoteException ex) { remove(r. binder); } } if((events & PhoneStateListener.LISTEN_DATA_ACTIVITY) != 0) { try{ r.callback.onDataActivity( mDataActivity); } catch(RemoteException ex) { remove(r. binder); } } if((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) { try{ r.callback.onSignalStrengthsChanged( mSignalStrength); } catch(RemoteException ex) { remove(r. binder); } } if((events & PhoneStateListener.LISTEN_OTASP_CHANGED) != 0) { try{ r.callback.onOtaspChanged( mOtaspMode); } catch(RemoteException ex) { remove(r. binder); } } if(validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO)) { try{ if(DBG_LOC ) Slog.d (TAG ,"listen: mCellInfo="+ mCellInfo); r.callback.onCellInfoChanged( mCellInfo); } catch(RemoteException ex) { remove(r. binder); } } } } } else{ remove(callback.asBinder()); } }
(20).当TelephonyRegistry 的notifyDataConnection()方法中触发 onDataConnectionStateChanged()时,实际上将回调到以下地方:具体都是做一些更新的操作
a.在framework 中NetworkController.java
@Override publicvoidonDataConnectionStateChanged (intstate,intnetworkType) { if(DEBUG ) { Slog. d(TAG, "onDataConnectionStateChanged : state=" + state + " type="+ networkType); } mDataState= state; mDataNetType= networkType; updateDataNetType(); updateDataIcon();// 更新数据图标 refreshViews();// 刷新view }
b.在framework 中NetworkStatsService.java
private PhoneStateListener mPhoneListener=new PhoneStateListener() { @Override publicvoidonDataConnectionStateChanged (intstate,intnetworkType) { finalbooleanstateChanged = state !=mLastPhoneState ; finalbooleannetworkTypeChanged = networkType !=mLastPhoneNetworkType; if(networkTypeChanged && !stateChanged) { // networkType changed without a state change, which means we // need to roll our own update. delay long enough for // ConnectivityManager to process. //TODO: add direct event to ConnectivityService instead of // relying on this delay. if(LOGV ) Slog.v (TAG ,"triggering delayed updateIfaces()"); mHandler.sendMessageDelayed( mHandler.obtainMessage(MSG_UPDATE_IFACES), SECOND_IN_MILLIS);//发消息进行更新 } mLastPhoneState= state; mLastPhoneNetworkType= networkType; } };
c.在应用程序Setting中 Status.java中:
private PhoneStateListener mPhoneStateListener= newPhoneStateListener() { @Override publicvoidonDataConnectionStateChanged (int state) { updateDataState();// updateNetworkType(); } }
d.在应用程序Setting中 RadioInfo.java中:
public void onDataConnectionStateChanged(intstate) { updateDataState(); updateDataStats(); updatePdpList(); updateNetworkType(); }
(21).TelephonyRegistry的 notifyDataConnection()方法最后调用 broadcastDataConnectionStateChanged ()方法发送数据连接变化的广播.这里将当前的状态, apn类型,连接参数等都封装在了 action为ACTION_ANY_DATA_CONNECTION_STATE_CHANGED_MOBILE的intent 中,通过intent将这些内容发送出去。之后 frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/toolbar/QuickSettingsConnectionModel.java 和/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/toolbar/SimSwitchPanel.java 将接收到该广播并进行处理。
private void broadcastDataConnectionStateChanged( intstate, booleanisDataConnectivityPossible, String reason, String apn, String apnType, LinkProperties linkProperties, LinkCapabilities linkCapabilities, booleanroaming) { // Note: not reporting to the battery stats service here, because the // status bar takes care of that after taking into account all of the // required info. Intent intent =newIntent(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED_MOBILE); intent.putExtra(PhoneConstants. STATE_KEY, DefaultPhoneNotifier.convertDataState(state).toString()); if(!isDataConnectivityPossible) { intent.putExtra(PhoneConstants. NETWORK_UNAVAILABLE_KEY,true ); } if(reason !=null) { intent.putExtra(PhoneConstants. STATE_CHANGE_REASON_KEY, reason); } if(linkProperties !=null) { intent.putExtra(PhoneConstants. DATA_LINK_PROPERTIES_KEY, linkProperties); String iface = linkProperties.getInterfaceName(); if(iface !=null) { intent.putExtra(PhoneConstants. DATA_IFACE_NAME_KEY, iface); } } if(linkCapabilities !=null) { intent.putExtra(PhoneConstants. DATA_LINK_CAPABILITIES_KEY , linkCapabilities); } if(roaming) intent.putExtra(PhoneConstants.DATA_NETWORK_ROAMING_KEY, true); intent.putExtra(PhoneConstants. DATA_APN_KEY, apn); intent.putExtra(PhoneConstants. DATA_APN_TYPE_KEY, apnType); if(FeatureOption.MTK_GEMINI_SUPPORT) { intent.putExtra(PhoneConstants. GEMINI_SIM_ID_KEY,mySimId ); } // To make sure MobileDataStateTracker can receive this intent firstly, // using oredered intent ACTION_ANY_DATA_CONNECTION_STATE_CHANGED_MOBILE // redirect original intent. --> mContext.sendOrderedBroadcast(intent,null,mDataConnChangeReceiver, null, 0,null,null); // <-- }
(21).在广播ACTION_ANY_DATA_CONNECTION_STATE_CHANGED_MOBILE发送之后,将被 MobileDataStateTracker中的内部类MobileDataStateReceiver和 TelephonyRegistry的mDataConnChangeReceiver 接收。TelephonyRegistry中将接收到 intent又使用action :TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED发送出去。
而在 MobileDataStateReceiver中处理则比较复杂,这里就没有不再进行细致分析了。先根据 intent中的apntype 从全局的trakerMap中取出相应的 tracker 实例,再根据PhoneConstants. STATE_KEY 取出 state值,并由此进行分支处理。在 CONNECTED 分支中, tracker调用setDetailedState() 修改apn对应的 networkinfo中的状态信息,并发送EVENT_STATE_CHANGED消息 ,ConnectionService的内部类NetworkStateTrackerHandler 将接收该消息并进行处理。
@Override public void onReceive(Context context, Intent intent) { if(intent.getAction().equals(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED_MOBILE)) { String apnType = intent.getStringExtra(PhoneConstants. DATA_APN_TYPE_KEY); MobileDataStateTracker tracker = mTrackerMap.get(apnType); if(tracker ==null) { return; } ...... // 子类型改变了,发出相应的消息 tracker. mNetworkInfo.setSubtype(newSubType, subTypeName); if(newSubType != oldSubtype && tracker.mNetworkInfo.isConnected()) { Message msg = tracker.mTarget.obtainMessage(EVENT_NETWORK_SUBTYPE_CHANGED, oldSubtype, 0, tracker.mNetworkInfo ); msg.sendToTarget(); } // 根据intent中传递过来的字符串 state值再次转换为 PhoneConstants.DataState ,并根据 state进行分支处理 PhoneConstants.DataState state = Enum. valueOf(PhoneConstants.DataState.class, intent.getStringExtra(PhoneConstants. STATE_KEY)); String reason = intent.getStringExtra(PhoneConstants. STATE_CHANGE_REASON_KEY); String apnName = intent.getStringExtra(PhoneConstants. DATA_APN_KEY); tracker.mNetworkInfo .setRoaming(intent.getBooleanExtra(PhoneConstants. DATA_NETWORK_ROAMING_KEY,false )); if(VDBG ) { tracker.log(tracker. mApnType+" setting isAvailable to " + !intent.getBooleanExtra(PhoneConstants. NETWORK_UNAVAILABLE_KEY,false )); } tracker.mNetworkInfo .setIsAvailable(!intent.getBooleanExtra(PhoneConstants. NETWORK_UNAVAILABLE_KEY,false )); if(tracker.mMobileDataState != state) { tracker. mMobileDataState= state; switch(state) { caseDISCONNECTED: if(tracker.isTeardownRequested()) { tracker.setTeardownRequested( false); } if(FeatureOption.MTK_GEMINI_SUPPORT) { tracker.setDetailedStateGemini(DetailedState. DISCONNECTED, reason, apnName, slot); } else{ tracker.setDetailedState(DetailedState. DISCONNECTED, reason, apnName); } // can't do this here - ConnectivityService needs it to clear stuff // it's ok though - just leave it to be refreshed next time // we connect. //if (DBG) log("clearing mInterfaceName for "+ mApnType + // " as it DISCONNECTED"); //mInterfaceName = null; break; caseCONNECTING: if(FeatureOption.MTK_GEMINI_SUPPORT) { tracker.setDetailedStateGemini(DetailedState. CONNECTING, reason, apnName, slot); } else{ tracker.setDetailedState(DetailedState. CONNECTING, reason, apnName); } break; caseSUSPENDED: if(FeatureOption.MTK_GEMINI_SUPPORT) { tracker.setDetailedStateGemini(DetailedState. SUSPENDED, reason, apnName, slot); } else{ tracker.setDetailedState(DetailedState. SUSPENDED, reason, apnName); } break; caseCONNECTED: tracker. mLinkProperties= intent.getParcelableExtra( PhoneConstants. DATA_LINK_PROPERTIES_KEY); if(tracker.mLinkProperties ==null) { tracker.loge( "CONNECTED event did not supply link properties." ); tracker. mLinkProperties=new LinkProperties(); } tracker. mLinkCapabilities= intent.getParcelableExtra( PhoneConstants. DATA_LINK_CAPABILITIES_KEY ); if(tracker.mLinkCapabilities ==null) { tracker.loge( "CONNECTED event did not supply link capabilities." ); tracker. mLinkCapabilities=new LinkCapabilities(); } if(FeatureOption.MTK_GEMINI_SUPPORT) { tracker.setDetailedStateGemini(DetailedState. CONNECTED, reason, apnName, slot); } else{ tracker.setDetailedState(DetailedState. CONNECTED, reason, apnName); } break; } } ..... }
privatevoid setDetailedState(NetworkInfo.DetailedState state, String reason, String extraInfo) { if(state !=mNetworkInfo .getDetailedState()) { booleanwasConnecting = (mNetworkInfo .getState() == NetworkInfo.State. CONNECTING); String lastReason = mNetworkInfo.getReason(); /* * If a reason was supplied when the CONNECTING state was entered, and no * reason was supplied for entering the CONNECTED state, then retain the * reason that was supplied when going to CONNECTING. */ if(wasConnecting && state == NetworkInfo.DetailedState.CONNECTED&& reason == null && lastReason != null) reason = lastReason; mNetworkInfo.setDetailedState(state, reason, extraInfo);//修改networkInfo 中的状态信息 Message msg =mTarget.obtainMessage(EVENT_STATE_CHANGED, newNetworkInfo(mNetworkInfo ));//给ConnectionService 中NetworkStateTrackerHandler发消息 msg.sendToTarget(); } elseif(reason !=null&& (reason.equals(PhoneConstants. REASON_NO_SUCH_PDP) || reason.equals(Phone.REASON_APN_FAILED )) && state == DetailedState. DISCONNECTED){ mNetworkInfo.setDetailedState(state, reason, extraInfo); Message msg = mTarget.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo); msg.sendToTarget(); } }
(22).回到ConnectionService.java 中来,这里果然是连接管理的最核心啊,也是反馈的终点了。
private class NetworkStateTrackerHandler extendsHandler { ..... @Override publicvoidhandleMessage(Message msg) { NetworkInfo info; switch(msg.what ) { caseNetworkStateTracker.EVENT_STATE_CHANGED: info = (NetworkInfo) msg. obj; inttype = info.getType(); NetworkInfo.State state = info.getState(); if(VDBG || (state == NetworkInfo.State.CONNECTED) || (state == NetworkInfo.State. DISCONNECTED)) { log("ConnectivityChange for "+ info.getTypeName() + ": "+ state + "/"+ info.getDetailedState()); } EventLogTags.writeConnectivityStateChanged( info.getType(), info.getSubtype(), info.getDetailedState().ordinal()); if(info.getDetailedState() == NetworkInfo.DetailedState. FAILED) { handleConnectionFailure(info); } elseif(info.getDetailedState() == DetailedState. CAPTIVE_PORTAL_CHECK) { handleCaptivePortalTrackerCheck(info); } elseif(state == NetworkInfo.State.DISCONNECTED) { handleDisconnect(info); } elseif(state == NetworkInfo.State.SUSPENDED) { //TODO: need to think this over. // the logic here is, handle SUSPENDED the same as // DISCONNECTED. The only difference being we are // broadcasting an intent with NetworkInfo that's // suspended. This allows the applications an // opportunity to handle DISCONNECTED and SUSPENDED // differently, or not. Slog. d(TAG, "Change to Suspend_State due to reason=" + info.getReason() +" with network="+ info.getSubtypeName()) ; if(((info.getReason() !=null) && info.getReason().equals(Phone.REASON_VOICE_CALL_STARTED )) && (info.getSubtype() == TelephonyManager. NETWORK_TYPE_GPRS || info.getSubtype() == TelephonyManager.NETWORK_TYPE_EDGE || info.getSubtype() == TelephonyManager.NETWORK_TYPE_UNKNOWN)) { Xlog.e( MTK_TAG,"Suspend PS TX/RX Temporarily without deactivating PDP context"); sendSuspendedBroadcast(info);// 手机2G网络挂起 } else{ Xlog.e( MTK_TAG,"Switch to Suspend:invoke handleDisconnect()" ); handleDisconnect(info);// 做断开处理 } } elseif(state == NetworkInfo.State.CONNECTED) { handleConnect(info);// 做连接处理 } if(mLockdownTracker !=null) { mLockdownTracker.onNetworkInfoChanged(info); } break; ....... } } }
(23.)最后一步操作了,根据NetworkInfo对应状态变化执行 handleConnect(进行Connected 处理)或者 handleDisconnect(Disconnected)处理。并发出 CONNECTIVITY_ACTION 的广播,该广播是一个公共广播,应用程序或者框架中都可以进行广播的接收。消息传递给应用程序,知晓了网络的连接状况已经改变,并且可以获取到具体当前的网络状态
private void handleDisconnect(NetworkInfo info) {
………
/* * If the disconnected network is not the active one, then don't report * this as a loss of connectivity. What probably happened is that we're * getting the disconnect for a network that we explicitly disabled * in accordance with network preference policies. */ if(!mNetConfigs [prevNetType].isDefault()) { List pids = mNetRequestersPids[prevNetType]; for(int i = 0; i<pids.size(); i++) { Integer pid = (Integer)pids.get(i); // will remove them because the net's no longer connected // need to do this now as only now do we know the pids and // can properly null things that are no longer referenced. reassessPidDns(pid.intValue(), false); } } Intent intent =new Intent(ConnectivityManager.CONNECTIVITY_ACTION); intent.putExtra(ConnectivityManager. EXTRA_NETWORK_INFO, new NetworkInfo(info)); intent.putExtra(ConnectivityManager. EXTRA_NETWORK_TYPE, info.getType()); if(info.isFailover()) { intent.putExtra(ConnectivityManager. EXTRA_IS_FAILOVER,true ); info.setFailover( false); } if(info.getReason() !=null) { intent.putExtra(ConnectivityManager. EXTRA_REASON, info.getReason()); } if(info.getExtraInfo() !=null) { intent.putExtra(ConnectivityManager. EXTRA_EXTRA_INFO, info.getExtraInfo()); } if(mNetConfigs [prevNetType].isDefault()) { /** M: Support CMCC Wi-Fi to Mobile @{ */ booleanmobileData = getMobileDataEnabled(); log("mobileData="+ mobileData + ", prevNetType="+ prevNetType +",mActiveDefaultNetwork "+mActiveDefaultNetwork); if(mIcsExt ==null){ log("Null in mIcsExt"); return; } if(mIcsExt .isDefaultFailover(prevNetType,mActiveDefaultNetwork)){ isFailover = tryFailover(prevNetType); if(mActiveDefaultNetwork != -1) { NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork ].getNetworkInfo(); intent.putExtra(ConnectivityManager. EXTRA_OTHER_NETWORK_INFO, switchTo); } else{ mDefaultInetConditionPublished= 0;// we're not connected anymore intent.putExtra(ConnectivityManager. EXTRA_NO_CONNECTIVITY,true ); } } else{ mDefaultInetConditionPublished= 0;// we're not connected anymore intent.putExtra(ConnectivityManager. EXTRA_NO_CONNECTIVITY,true ); mActiveDefaultNetwork= -1; if(!mIcsExt .isUserPrompt()) { isFailover = tryFailover(prevNetType); if(mActiveDefaultNetwork != -1) { NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork ].getNetworkInfo(); intent.putExtra(ConnectivityManager. EXTRA_OTHER_NETWORK_INFO, switchTo); } else{ mDefaultInetConditionPublished= 0;// we're not connected anymore intent.putExtra(ConnectivityManager. EXTRA_NO_CONNECTIVITY,true ); } } } /** M: @} */ } intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished); if(FeatureOption.MTK_GEMINI_SUPPORT) { if(ConnectivityManager.isRadioNumValid(simId)) { intent.putExtra(ConnectivityManager. EXTRA_SIM_ID,simId); } } // Reset interface if no other connections are using the same interface booleandoReset =true; LinkProperties linkProperties = mNetTrackers[prevNetType].getLinkProperties(); if(linkProperties !=null) { String oldIface = linkProperties.getInterfaceName(); if(TextUtils.isEmpty(oldIface) == false) { for(NetworkStateTracker networkStateTracker :mNetTrackers) { if(networkStateTracker ==null)continue; NetworkInfo networkInfo = networkStateTracker.getNetworkInfo(); if(networkInfo.isConnected() && networkInfo.getType() != prevNetType) { LinkProperties l = networkStateTracker.getLinkProperties(); if(l ==null)continue; if(oldIface.equals(l.getInterfaceName())) { doReset = false; break; } } } } } // do this before we broadcast the change handleConnectivityChange(prevNetType, doReset); finalIntent immediateIntent =newIntent(intent); immediateIntent.setAction( CONNECTIVITY_ACTION_IMMEDIATE ); sendStickyBroadcast(immediateIntent); sendStickyBroadcastDelayed(intent, getConnectivityChangeDelay()); /* * If the failover network is already connected, then immediately send * out a followup broadcast indicating successful failover */ if(mActiveDefaultNetwork != -1) { sendConnectedBroadcastDelayed( mNetTrackers[mActiveDefaultNetwork ].getNetworkInfo(), getConnectivityChangeDelay()); } /* whenever any interface is down, try to restore default */ if(FeatureOption.MTK_DT_SUPPORT !=true) { if(!isFailover) { tryRestoreDefault(); } } } pivate void handleConnect(NetworkInfo info) { finalintnewNetType = info.getType(); setupDataActivityTracking(newNetType); // snapshot isFailover, because sendConnectedBroadcast() resets it booleanisFailover = info.isFailover(); finalNetworkStateTracker thisNet =mNetTrackers [newNetType]; finalString thisIface = thisNet.getLinkProperties().getInterfaceName(); // if this is a default net and other default is running // kill the one not preferred if(mNetConfigs [newNetType].isDefault()) {//是否是默认网络 if(mActiveDefaultNetwork != -1 &&mActiveDefaultNetwork!= newNetType) { if(isNewNetTypePreferredOverCurrentNetType(newNetType)) {//网络优先级判断,wifi开启的情况下,数据网络会在这里通过 tearDown关掉 // tear down the other NetworkStateTracker otherNet = mNetTrackers[mActiveDefaultNetwork ]; if(DBG ) { log("Policy requires "+ otherNet.getNetworkInfo().getTypeName() + " teardown"); } if(!teardown(otherNet)) { loge("Network declined teardown request"); //MTK mark Xlog.e(MTK_TAG, "Since we may teardown it by other way, just go on" ); //teardown (thisNet); //return; } } else{ // don't accept this one if(VDBG ) { log("Not broadcasting CONNECT_ACTION "+ "to torn down network " + info.getTypeName()); } teardown(thisNet); return; } } synchronized(ConnectivityService.this) { // have a new default network, release the transition wakelock in a second // if it's held. The second pause is to allow apps to reconnect over the // new network if(mNetTransitionWakeLock .isHeld()) { mHandler.sendMessageDelayed(mHandler .obtainMessage( EVENT_CLEAR_NET_TRANSITION_WAKELOCK , mNetTransitionWakeLockSerialNumber , 0), 1000); } } mActiveDefaultNetwork= newNetType; // this will cause us to come up initially as unconnected and switching // to connected after our normal pause unless somebody reports us as reall // disconnected mDefaultInetConditionPublished= 0; mDefaultConnectionSequence++; mInetConditionChangeInFlight=false ; // Don't do this - if we never sign in stay, grey //reportNetworkCondition(mActiveDefaultNetwork, 100); } thisNet.setTeardownRequested( false); updateNetworkSettings(thisNet); handleConnectivityChange(newNetType, false); sendConnectedBroadcastDelayed(info, getConnectivityChangeDelay()); // notify battery stats service about this network finalString iface = thisNet.getLinkProperties().getInterfaceName(); if(iface !=null) { try{ BatteryStatsService. getService().noteNetworkInterfaceType(iface, newNetType); } catch(RemoteException e) { // ignored; service lives in system_server } } } --------------------------------------------------------------
private void sendConnectedBroadcastDelayed(NetworkInfo info, intdelayMs) { sendGeneralBroadcast(info, CONNECTIVITY_ACTION_IMMEDIATE ); sendGeneralBroadcastDelayed(info, CONNECTIVITY_ACTION, delayMs); }
相关文章推荐
- Android实现启用GPRS/3G网络
- MTK: android: TD、HSPA、GPRS的projectconfig.mk配置:
- MTK Android平台系统语言处理流程
- MTK Android Camera 运行流程-app到底层
- MTK Android平台开发流程
- Android建立GPRS通信的流程
- MTK (android 开机)Android开机流程解析
- MTK Android Camera 运行流程
- MTK Android Camera 运行流程
- android MTK驱动背光唤醒流程
- Android Sensor (MTK) 整体架构流程(GSensor)
- Android 6.0(M) BatteryService浅析及充电呼吸灯流程浅析 MTK
- MTK平台相关总结#########[FAQ18279]开机时间慢分析 android 系统重启关机流程分析
- android MTK驱动背光唤醒流程
- Android启动流程分析之一:Bootloader(基于高通芯片) 【mtk lk阶段有类似】
- android MTK驱动背光唤醒流程
- android MTK驱动背光唤醒流程
- MTK android recovery模式流程
- Android GSM驱动模块(rild)详细分析(三)response流程