大概了解Mms机制,发现发送彩信时,使用的是另一路APN。因此以此为追踪入口。

     MmsNetworkManager.java>>>connectivityManager.requestNetwork(mNetworkRequest, mNetworkCallback, NETWORK_REQUEST_TIMEOUT_MILLIS);
  • 1
  • 2
  • 3

mNetworkRequest.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS),为后面的APN匹配查找给出了条件。 
mNetworkCallback作为request后的调用响应,将把申请的Network返回。此Network带有ID,每次创建释放后递增。Mms根据此Network来查询Mms对应的APN信息。

ConnectivityService.java
>>>requestNetwork()
>>>handleRegisterNetworkRequest(Message msg)
  • 1
  • 2
  • 3

以Mms类型创建NetworkRequest对象和NetworkRequestInfo对象,以键值对形式保存到mNetworkRequests中:

mNetworkRequests.put(nri.request, nri);
if (DBG) log("sending new NetworkRequest to factories")
//此时network.satisfies(nri.request)为false,并且bestNetwork为null。for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) {nfi.asyncChannel.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score,0, nri.request);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

mNetworkFactoryInfos对象来源于

    public void registerNetworkFactory(Messenger messenger, String name) {enforceConnectivityInternalPermission();NetworkFactoryInfo nfi = new NetworkFactoryInfo(name, messenger, new AsyncChannel());mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_FACTORY, nfi));
  • 1
  • 2
  • 3
  • 4

过程如下: 
在Phone的初始化中调用,

PhoneFactory.makeDefaultPhones(this)ProxyController.getInstance(context, sProxyPhones,mUiccController, sCommandsInterfaces)DctController.makeDctController(phoneProxy)updatePhoneBaseForIndex(i, phoneBase)mNetworkFactory[index] = new TelephonyNetworkFactory(this.getLooper(),mPhones[index].getContext(), "TelephonyNetworkFactory", phoneBase,mNetworkFilter[index]);mNetworkFactory[index].setScoreFilter(50);mNetworkFactoryMessenger[index] = new Messenger(mNetworkFactory[index]);cm.registerNetworkFactory(mNetworkFactoryMessenger[index], "Telephony");
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

此处两个关键点: 
1.mNetworkFactory[index] = new TelephonyNetworkFactory() 
TelephonyNetworkFactory继承于NetworkFactory,其使用DctController内部的Looper对象,并且将调用到NetworkFactory.java::handleMessage()

2.cm.registerNetworkFactory(mNetworkFactoryMessenger[index], “Telephony”)调用上面的注册函数

NetworkFactory.java>>>handleAddRequest(NetworkRequest request, int score)
>>>evalRequest(NetworkRequestInfo n)               //此时为TelephonyNetworkFactory对象,其继承于NetworkFactory。TelephonyNetworkFactory为DctController.java的内部类
  • 1
  • 2
  • 3
  • 4

打印 :[TNF 1]evalRequest request = NetworkRequest [ id=4, legacyType=2, 
[ Transports: CELLULAR Capabilities: 
MMS&NOT_RESTRICTED&TRUSTED&NOT_VPN Specifier: <1>] ] with requested = 
false

DctController.java
private class TelephonyNetworkFactory extends NetworkFactory
>>>needNetworkFor(NetworkRequest networkRequest, int score)String apn = apnForNetworkRequest(networkRequest);     //apnForNetworkRequest()函数通过nr.networkCapabilities,即Mms中requestNetwork传入的Mms类型进行匹配,返回PhoneConstants.APN_TYPE_MMS。if (dcTracker.isApnSupported(apn)) {requestNetwork(networkRequest, dcTracker.getApnPriority(apn), mGroupId);} else {log("Unsupported APN");}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

>>>requestNetwork(NetworkRequest request, int priority, int gid)
  • 1
  • 2

打印:[DctController] requestNetwork request=NetworkRequest [ id=3, 
legacyType=2, [ Transports: CELLULAR Capabilities: 
MMS&NOT_RESTRICTED&TRUSTED&NOT_VPN Specifier: <1>] ], priority=2, gid 
= 0

mRequestInfos以键值对保存request.requestId和requestInfo。

>>>onProcessGroup(int group)if (mDataAllowed) {               //mDataAllowed默认为true,除非setDataAllowed()的主动调用设置false。if (activePhoneId == -1 || activePhoneId == phoneId) {Iterator<Integer> iterator = mRequestInfos.keySet().iterator();if (activePhoneId == -1 && !iterator.hasNext()) {logd("No active phone, set phone" + phoneId + " to attaching state");transitToAttachingState(phoneId);}while (iterator.hasNext()) {RequestInfo requestInfo = mRequestInfos.get(iterator.next());         //取出requestNetwork()住保存的requestInfo变量if (getRequestPhoneId(requestInfo.request) == phoneId&& requestInfo.mGId == group&& !requestInfo.executed) {mDcSwitchAsyncChannel[phoneId].connectSync(requestInfo);          //发起connect请求}}} else {mDcSwitchAsyncChannel[activePhoneId].disconnectAllSync();}}DcSwitchAsyncChannel.java
>>>connectSync(RequestInfo apnRequest)
Message response = sendMessageSynchronously(REQ_CONNECT, apnRequest)
**//此处是sendMessageSynchronously(),其实现在AsyncChannel.java中,静态内部类SyncMessenger,标准的同步消息队列,通过其内部对象对象 sm.mHandler.mLockObject来完成:**public void handleMessage(Message msg) {mResultMsg = Message.obtain();mResultMsg.copyFrom(msg);synchronized(mLockObject) {mLockObject.notify();}}private static Message sendMessageSynchronously(Messenger dstMessenger, Message msg) {SyncMessenger sm = SyncMessenger.obtain();try {if (dstMessenger != null && msg != null) {msg.replyTo = sm.mMessenger;synchronized (sm.mHandler.mLockObject) {dstMessenger.send(msg);sm.mHandler.mLockObject.wait();}
...
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

过程如下: 
在构造函数中,

            int status = mDcSwitchAsyncChannel[i].fullyConnectSync(mPhones[i].getContext(),mDcSwitchStateHandler[i], mDcSwitchStateMachine[i].getHandler());
  • 1
  • 2

和下面的分析类似,此时mDcSwitchStateMachine[i].getHandler()即为sendMessageSynchronously()的目的地Looper队列。 
在DcSwitchStateMachine构造函数中,使用super(name)方式,即状态机内部新建一个HandlerThread,使用自己的新建内部Looper队列:

    protected StateMachine(String name) {mSmThread = new HandlerThread(name);mSmThread.start();Looper looper = mSmThread.getLooper();initStateMachine(name, looper);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

//DcSwitchStateMachine的默认状态是setInitialState(mIdleState)。此处为分析Mms请求过程,继而会直接到AttachedState状态

DcSwitchStateMachine.java
private class AttachedState extends State {
...case DcSwitchAsyncChannel.REQ_CONNECT: {RequestInfo apnRequest = null;if (msg.obj != null) {apnRequest = (RequestInfo) msg.obj;DctController.getInstance().executeRequest(apnRequest);     //apnRequest=[ request=NetworkRequest [ id=3, legacyType=2, [ Transports: CELLULAR Capabilities: MMS&NOT_RESTRICTED&TRUSTED&NOT_VPN Specifier: <1>] ], executed=false, priority=2, gid=0, phoneId=0]}if (DBG) {log("AttachedState: REQ_CONNECT, apnRequest=" + apnRequest);}mAc.replyToMessage(msg, DcSwitchAsyncChannel.RSP_CONNECT,PhoneConstants.APN_REQUEST_STARTED);retVal = HANDLED;break;}
...
}DctController.java
>>>executeRequest(RequestInfo request)
>>>onExecuteRequest(RequestInfo requestInfo)if (needExecuteRequest(requestInfo)) {            //   needExecuteRequest()查询requestInfo.executed是否为true,若是则返回false。requestInfo.executed = true;String apn = apnForNetworkRequest(requestInfo.request);int phoneId = getRequestPhoneId(requestInfo.request);logd("onExecuteRequest apn = " + apn + " phoneId=" + phoneId);     //打印:[DctController] onExecuteRequest apn = mms phoneId=0requestInfo.phoneId = phoneId; // remember the executed phone id.PhoneBase phoneBase = getActivePhone(phoneId);DcTrackerBase dcTracker = phoneBase.mDcTracker;               //每个PhoneBase对应一个DcTrackerdcTracker.incApnRefCount(apn);}DcTracker.java
>>>incApnRefCount(String name)ApnContext apnContext = mApnContexts.get(name);     //此处的name为mms,mApnContexts以name为key,保存了不同网络类型对应的ApnContext对象log("incApnRefCount name = " + name);if (apnContext != null) {log("incApnRefCount apnContext = " + apnContext);apnContext.incRefCount();                                        //ApnContext基于res下的config.xml中的networkAttributes数组,通过DcTrack中的initApnContexts()完成初始化。}ApnContext.java
>>>incRefCount()synchronized (mRefCountLock) {if (mRefCount++ == 0) {mDcTracker.setEnabled(mDcTracker.apnTypeToId(mApnType), true);}}DcTrackerBase.java>>>setEnabled(int id, boolean enable)              
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57

//打印:request,setEnabled(1, true) with old state = false and 
enabledCount = 1。release,setEnabled(1, true) with old state = false 
and enabledCount = 1

DcTracker.java>>>onEnableApn(int apnId, int enabled)
>>>applyNewState(ApnContext apnContext, boolean enabled, boolean met)
"applyNewState(" + apnContext.getApnType() + ", " + enabled +"(" + apnContext.isEnabled() + "), " + met + "(" +apnContext.getDependencyMet() +"))"
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

//打印: applyNewState(mms, true(false), true(true)) if (trySetup) 
trySetupData(apnContext); //trySetup为true

>>>trySetupData(ApnContext apnContext, ArrayList<ApnSetting> waitingApns)     //此时 waitingApns为nullif (waitingApns == null) {waitingApns = buildWaitingApns(apnContext.getApnType(), radioTech);                  }...boolean retValue = setupData(apnContext, radioTech);
//buildWaitingApns ()根据传入的ApnType类型(mms) 去查询匹配的APN信息,并保存到waitingApns数组
/*/*** Build a list of APNs to be used to create PDP's.
**/
private ArrayList<ApnSetting> buildWaitingApns(String requestedApnType, int radioTech) {
...for (ApnSetting apn : mAllApnSettings) {        if (DBG) log("buildWaitingApns: apn=" + apn);if (apn.canHandleType(requestedApnType)) {if (apn.bearer == 0 || apn.bearer == radioTech) {if (DBG) log("buildWaitingApns: adding apn=" + apn.toString());apnList.add(apn);} else {if (DBG) {log("buildWaitingApns: bearer:" + apn.bearer + " != "+ "radioTech:" + radioTech);}}}
...
}
*/
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

mAllApnSettings为匹配核心变量。其在createAllApnList()中,通过mAllApnSettings = createApnList(cursor)被赋值。cursor定义如下:

            Cursor cursor = mPhone.getContext().getContentResolver().query(Telephony.Carriers.CONTENT_URI, null, selection, null, null);
  • 1
  • 2

此处Telephony.Carriers.CONTENT_URI是何时被赋值的?请自行研究。


>>>setupData(ApnContext apnContext, int radioTech)          //radioTech = mPhone.getServiceState().getRilDataRadioTechnology()用于后面的匹配是否支持多DC通路
  • 1
  • 2

//打印:setupData: apnContext={mApnType=mms mState=IDLE 
mWaitingApns={[[ApnSettingV3] 中国联通 Wap 网络 (China Unicom), 1153, 46001, 
3gwap, 10.0.0.172, , , , 80, -1, *, IPV4V6, IP, true, 0, 0, false, 0, 
0, 0, 0, , , [ApnSettingV3] 中国联通 3g 彩信 (China Unicom), 1154, 46001, 
3gwap, , http://mmsc.myuni.com.cn, 10.0.0.172, 80, , -1, mms, IPV4V6, 
IP, true, 0, 0, false, 0, 0, 0, 0, , ]} 
mWaitingApnsPermanentFailureCountDown=2 mApnSetting={null} 
mReason=dataEnabled mDataEnabled=true mDependencyMet=true}

   ...apnSetting = apnContext.getNextWaitingApn();     //getNextWaitingApn()函数返回apnContext数组的[0]...dcac = checkForCompatibleConnectedApnContext(apnContext);    //checkForCompatibleConnectedApnContext()函数会遍历mApnContexts,查询各个网络类型当前的Dcac通路,默认都是null。第一次发送Mms时,mms也为null。何时不为null?...if (dcac == null) {if (DBG) log("setupData: No ready DataConnection found!");// TODO: When allocating you are mapping type to id. If more than 1 free,// then could findFreeDataConnection get the wrong one??dcac = findFreeDataConnection();     //findFreeDataConnection()遍历mDataConnectionAcHashMap,是否有处于Inactive状态同时未被占用的dcac。第一次发送Mms时,返回null。当第二次发送Mms时,会返回之前创建的dcac对象}...if (dcac == null) {dcac = createDataConnection();     //MTK平台getPdpConnectionPoolSize()mtk上默认最大pdp连接数设定是3.}
...
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

createDataConnection(): 
1.创建DataConnection对象,并以自增的id为Key保存到mDataConnections 
2.建立对应的DcAsyncChannel对象,以同一个自增的id为Key保存到mDataConnectionAcHashMap 
3.在MTK的默认设计中,此自增id不能大于3,MTK对此解释: throttling/high throughput apn start 
(DataConnection类继承于StateMachine,在其构造函数中,会调用自己的start()函数,使StateMachine运行起来。)

>>>createDataConnection()
...DataConnection conn = DataConnection.makeDataConnection(mPhone, id,this, mDcTesterFailBringUpAll, mDcc);mDataConnections.put(id, conn);DcAsyncChannel dcac = new DcAsyncChannel(conn, LOG_TAG);int status = dcac.fullyConnectSync(mPhone.getContext(), this, conn.getHandler());
...
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

//dcac.fullyConnectSync(mPhone.getContext(), this, conn.getHandler()) 是一个关键调用:

AsyncChannel.java::    public void connected(Context srcContext, Handler srcHandler, Messenger dstMessenger) {if (DBG) log("connected srcHandler to the dstMessenger  E");RuntimeException here = new RuntimeException("here");here.fillInStackTrace();Slog.i(TAG, "CallTrace : ", here);       // Initialize source fieldsmSrcContext = srcContext;mSrcHandler = srcHandler;mSrcMessenger = new Messenger(mSrcHandler);// Initialize destination fieldsmDstMessenger = dstMessenger;if (DBG) log("connected srcHandler to the dstMessenger X");}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

请注意mDstMessenger = dstMessenger,此时调用端传入conn.getHandler(): 
conn是DataConnection类的对象,DataConnection继承于StateMachine,即conn.getHandler()为StateMachine的内部对象mSmHandler。仔细阅读代码后,会发现这个mSmHandler绕了一圈: 
DataConnection构造函数中,super(name, dcc.getHandler())—dcc为DcController对象,其也继承于StateMachine。 
DcTrackerBase构造函数中:

        HandlerThread dcHandlerThread = new HandlerThread("DcHandlerThread");dcHandlerThread.start();Handler dcHandler = new Handler(dcHandlerThread.getLooper());mDcc = DcController.makeDcc(mPhone, this, dcHandler);
  • 1
  • 2
  • 3
  • 4

总结:

...if(0 == apnContext.getDefaultBearerConfig().mIsValid) {dcac.bringUp(apnContext, getInitialMaxRetry(), profileId, radioTech, mAutoAttachOnCreation,msg);}
...DcAsyncChannel.java
>>>bringUp(ApnContext apnContext, int initialMaxRetry, int profileId,int rilRadioTechnology, boolean retryWhenSSChange, Message onCompletedMsg)
此函数注释为:     * Bring up a connection to the apn and return an AsyncResult in onCompletedMsg.* Used for cellular networks that use Acesss Point Names (APN) such* as GSM networks.AsyncChannel.java>>>sendMessage(Message msg){msg.replyTo = mSrcMessenger;try {mDstMessenger.send(msg);     //mDstMessenger将msg发送到目标Handler,其为DcInactiveState。是如何联系上的???} catch (RemoteException e) {replyDisconnected(STATUS_SEND_UNSUCCESSFUL);}    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

打印log如下: 
Line 5121: 06-27 11:28:45.152 1397 1481 D DC-2 : DcInactiveState nothandled msg.what=CMD_CHANNEL_FULL_CONNECTION 
Line 5122: 06-27 11:28:45.152 1397 1481 D DC-2 : DcDefault msg=CMD_CHANNEL_FULL_CONNECTION RefCount=0 
Line 5123: 06-27 11:28:45.152 1397 1481 D DC-2 : DcDefaultState: FULL_CONNECTION reply connected 
Line 5131: 06-27 11:28:45.155 1397 1397 D DC-2 : makeNetworkCapabilities: check data enable:true Line 5132: 06-27 
11:28:45.157 1397 1397 D DCT : [0]createDataConnection() X id=1 
dc={DC-2: State=DcInactiveState mApnSetting=null RefCount=0 mCid=-1 
mCreateTime=-1 mLastastFailTime=-1 mLastFailCause=NONE mTag=1 
mRetryManager=RetryManager: { forever=false maxRetry=0 curMaxRetry=0 
retry=0 config={null} retryArray={}} mLinkProperties={LinkAddresses: 
[] Routes: [] DnsAddresses: [] Domains: null MTU: 0 PcscfAddresses: 
[] } linkCapabilities=[ Transports: CELLULAR Capabilities: 
NOT_RESTRICTED&TRUSTED&NOT_VPN LinkUpBandwidth>=51200Kbps 
LinkDnBandwidth>=102400Kbps Specifier: <1>] mApnContexts=[]} 
Line 5133: 06-27 11:28:45.158 1397 1397 D DCT : [0]setupData: dcac=DC-2 apnSetting=[ApnSettingV3] 中国联通 Wap 网络 (China 
Unicom), 1153, 46001, 3gwap, 10.0.0.172, , , , 80, -1, *, IPV4V6, IP, 
true, 0, 0, false, 0, 0, 0, 
Line 5140: 06-27 11:28:45.161 1397 1481 D DC-2 : DcInactiveState nothandled 
msg.what=EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED 
Line 5141: 06-27 11:28:45.161 1397 1481 D DC-2 : DcDefault msg=EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED RefCount=0 
Line 5142: 06-27 11:28:45.161 1397 1481 D DC-2 : DcDefaultState: EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED drs=0 
mRilRat=14 
Line 5144: 06-27 11:28:45.162 1397 1481 D DC-2 : DcInactiveState nothandled msg.what=EVENT_DATA_CONNECTION_ROAM_OFF 
Line 5145: 06-27 11:28:45.162 1397 1481 D DC-2 : DcDefault msg=EVENT_DATA_CONNECTION_ROAM_OFF RefCount=0 
Line 5164: 06-27 11:28:45.175 1397 1481 D DC-2 : DcInactiveState: mag.what=EVENT_CONNECT

上面已经说明mDstMessenger目的Looper,其为DataConnection以及DcController两个状态机对象对应Looper。在DataConnection构造函数中:

            addState(mDefaultState);addState(mInactiveState, mDefaultState);addState(mActivatingState, mDefaultState);addState(mRetryingState, mDefaultState);addState(mActiveState, mDefaultState);addState(mDisconnectingState, mDefaultState);addState(mDisconnectingErrorCreatingConnection, mDefaultState);setInitialState(mInactiveState);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

结合上面log,在EVENT_CONNECT到来之前的几条msg处理,并未转换状态,继而直接被DcInactiveState处理。

DataConnection.java
>>>private class DcInactiveState extends State {public boolean processMessage(Message msg){
...               case EVENT_CONNECT:if (DBG) log("DcInactiveState: mag.what=EVENT_CONNECT");
...if (initConnection(cp)) {               //检查cp参数的兼容性,其mApnSetting是否为null,亦或Apntype是否可以被处理。不返回false的时候,将cp赋给mConnectionParamsonConnect(mConnectionParams);transitionTo(mActivatingState);     //状态切换,将首先运行mActivatingState的enter()函数.}
...}
}>>>onConnect(ConnectionParams cp)
此函数注释为:/*** Begin setting up a data connection, calls setupDataCall* and the ConnectionParams will be returned with the* EVENT_SETUP_DATA_CONNECTION_DONE AsyncResul.userObj.*/
...if (1 == cp.mDefaultBearerConfig.mIsValid ) {   //request from VA for VoLTEDefaultBearerConfig defaultBearerConfig = new DefaultBearerConfig();defaultBearerConfig.copyFrom(cp.mDefaultBearerConfig);mPhone.mCi.setupDataCall(Integer.toString(cp.mRilRat + 2),Integer.toString(cp.mProfileId),mApnSetting.apn, mApnSetting.user, mApnSetting.password,Integer.toString(authType),protocol, String.valueOf(mId + 1), defaultBearerConfig, msg);} else {/// M: [C2K][IRAT] Use RilArbitrator to setup data.setupDataCall(Integer.toString(cp.mRilRat + 2),Integer.toString(cp.mProfileId), mApnSetting.apn,mApnSetting.user, mApnSetting.password,Integer.toString(authType), protocol, String.valueOf(mId + 1),msg);}
...
//以上部分,MTK有做定制。核心调用mPhone.mCi.setupDataCall()。RIL.java>>>setupDataCall(String radioTechnology, String profile, String apn,String user, String password, String authType, String protocol,String interfaceId, DefaultBearerConfig defaultBearerConfig, Message result)
RILRequest rr= RILRequest.obtain(RIL_REQUEST_SETUP_DATA_CALL, result);
...
send(rr);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52

打印log如下: 
Line 5214: 06-27 11:28:45.201 1397 1481 D RILJ : [4160]> SETUP_DATA_CALL 16 0 3gwap 0 IPV4V6 2 [isValid=0, qos=[qci=0, 
dlGbr=0, ulGbr=0, dlMbr=0, ulMbr=0], emergency_ind=0, 
pcscf_discovery_flag=0, signaling_flag=0] 0 [SUB0] 
Line 5243: 06-27 11:28:45.207 719 732 D RILC : SOCKET RIL_SOCKET_1 REQUEST: SETUP_DATA_CALL length:180 
Line 5246: 06-27 11:28:45.207 719 732 D RILC-MTK: SETUP_DATA_CALL pRI=0xb6437280 p=0xb646f520 dispatched to 
RIL_CMD_PROXY_4 
Line 5267: 06-27 11:28:45.208 719 724 D RILC-MTK: SETUP_DATA_CALL pRI=0xb6437280 p=0xb646f520 execute on RIL_CMD_PROXY_4 
using channel 4 
Line 5269: 06-27 11:28:45.208 719 724 D RIL : onRequest: SETUP_DATA_CALL, datalen = 32 
Line 6218: 06-27 11:28:45.374 1397 1469 D RILJ : [4160]< SETUP_DATA_CALL DataCallResponse: {version=10 status=0 retry=0 cid=1 
active=2 type=IP ifname=ccmni1 mtu=0 addresses=[10.151.32.118] 
dnses=[221.4.8.1,221.4.8.1] gateways=[10.151.32.118] pcscf=[]} [SUB0]

以Mms的Apn信息创建新的PDP通路。上面的log可以看出,PDP通路建立后,会请求分配到运营商的内网IP。 
Mms在使用建立的通路发送完短信后,会调用releaseNetwork()释放此network,其过程可自行分析。

关于PDP的知识摘要:

(1)终端设备向移动终端发送AT指令激活IP协议,在指令中包含终端想要连接的APN(AccessPointName,访问点名称) 
(2)终端设备向移动终端发送PPPPLC帧给移动终端,表明PAP是在PDP激活过程中的身份认证协议 
(3)终端设备开始进行PAP认证,认证通过后,移动终端将对终端设备给以回应,表明承认其身份,并且会将用户ID和密码储存下来 
(4)终端设备通过发送NCP-IPCP配置请求信息给移动终端,帧内IP地址为空,表明请求动态分配IP地址 
(5)移动终端向SGSN(ServicingGPRSSupportNode,服务GPRS节点)发送激活PDP上下文的请求信息,信息中包含如下信息:APN、PDP类型,PDP地址为空,代表请求动态分配IP地址 
(6)SGSN请求DNS(DomainNameSystem,域名系统)服务器对APN进行解析,得到APN对应的GGSN的IP地址 
(7)SGSN发送建立PDP上下文的请求消息给被选定的GGSN,消息中应包含:APN、PDP类型,PDP地址为空,代表请求动态分配IP地址、用户更改的QoS和其他选项 
(8)GGSN对用户进行认证,认证通过后,使用RADIUS(RemoteAuthenticationDia-inUserService,远程认证拨入用户服务)服务器、DHCP(DynamicHostConfigurationProtocol,动态主机配置协议)服务器或直接由GGSN为用户分配动态IP地址,GGSN向SGSN返回建立PDP上下文相应消息 
(9)SGSN向移动终端发送激活PDP、上下文接受消息 
(10)移动终端发送NCP-IPCP配置回应帧给终端设备,回应帧包含了被动态分配的IP地址

一个PDP上下文提供了在UE和网络侧之间交换IP包的一个数据包连接。利用这个数据包连接可以访问一些特定的业务。PDP上下文一般来说主要有以下两个目的。第一点是PDP上下文设计用于分配一个PDP地址,或者是IPV4或者是IPV6地址给一个终端。第二点用于决定一个到终端的带有QOS profile的逻辑连接,即为一个PDP上下文协商的一组贯穿整个UMTS网络都能得到执行的QOS profile。 
由于移动终端的发展,他们需要同时在手机上建立多个并行的PS连接。这些PS连接,他们的QOS参数,以及访问的目标网络都有可能不同。多PDP上下文也就是说一个移动终端可以存在多个PDP上下文。其中第一个被创建的PDP就是Primary PDP,在Primary PDP的基础上可以创建多个Secondary PDP,这些Secondary PDP和Primary PDP拥有相同的IP地址也就是PDP地址,接入的网络类型是一样的,但是具有不同的Qos Profile,这样就产生了多Secondary PDP。如果接入的网络不一样,那就是多Primary PDP了,例如移动网络的CMWAP和CMNET,如果手机用户同时使用这两个网络上网,那么将会产生多个Primary PDP。上面介绍了多PDP Context的概念。同时也把多Primary PDP和多Secondary PDP介绍了。 
现在开始进入正题,用户开启多个应用访问网络的时候,IP地址的分配问题。首先看用户接入网络的类型,如果两个应用使用了不同的接入类型,例如一个使用CMWAP,一个使用CMNET,最后肯定会导致申请两个Primaey PDP,这样就会生成两个IP地址来进行数据传输,同时也会有2个NSAPI。如果用户使用一种接入方式的话。就不会产生新的IP地址。是否有Secondary PDP产生的话就要看用户使用的服务了。打个比方,如果用户首先浏览网页,这个时候生成看了一个Primary PDP,分配了IP地址、NSAPI、控制面和用户面TEID,紧跟着开启其他的相同Qos的业务的话,就不会产生Secondary PDP。如果新的业务是3g视频通信的话,需要很好的Qos,这样就会生成新的Secondary PDP,分配新的NSAPI、用户面TEID,注意控制面TEID和IP是不变的。具体使用什么样的Qos,这是开发软件者和运营商去协商。正常来说交钱少的就是直接使用Primary PDP了,交钱多的就会开启Secondary PDP来提高质量。 
注:平时上网我们一般是使用CMNET,但是在上网的同时,如果发送彩信的话,就会使用CMWAP了,这个时候应该就会出现多Primary PDP的情况。

gprs上网首先要设置pdp,接着建立ppp连接,ppp连接建立后,就可以进行tcp/ip传输了,要进行tcp/ip数据传输,很多时候都采用socket. 
PDP:是GPRS连接的软硬件环境,指定GPRS连接的接入点APN,连接类型IP或PPP,还有其他一些可选项; 
PPP:终端和MODEM之间点对点的协议,包括终端于MODEM之间的链路层协商(LCP),服务器对终端的认证(PAP或CHAP,这一步非强制),以及终端与服务器的网络层协商(基本都是IPCP); 
SOCKET:进程之间的通信方式,手机上的应用程序(客户进程)要和服务器的某个服务进程通信,就用socket通过邦定的TCP或UDP端口基于IP 
进行数据传输 
再补充一下: 
PPP协商过程中的IPCP配置中,终端通过MODEM请求激活PDP上下文获得IP地址完成网络连接,PDP中设置的APN就是终端所在的这个网络的网关,终端访问internet时就得通过这个网关; 而终端的客户进程与服务器的服务进程进行socket通信时,就基于这个IP地址。 
据我所知道的:从网络侧来看,PPP连接最重要的一步是获取IP地址,这个IP由GGSN分配,GGSN是GPRS网到internet的网关,GSM和WCDMA协议规定一个MODEM可以和多个GGSN建立PDP上下文,不知道你所说的服务器是否指GGSN。而socket连接的服务器和GGSN完全 
是两码事,socket连接的是internet网络中的服务器,socket是用于进程间通信的,它将进程与TCP/UDP端口进行绑顶,一个client端的socket只能连接一个server socket。也就决定了它只能连接一台服务器。

移动终端开机连接到运营商后,访问3G网络外部IPv6业务,主要包括以下三个过程: 
  (1)附着(ATTACH)。附着过程的目的是系统根据移动终端的签约数据确定是否允许移动终端在当前请求的GPRS路由区域中进行数据业务访问。附着过程与IPv6无关。 
  终端可以在开机通过无线接入鉴权获得无线信道后即向SGSN发起“附着请求”消息,SGSN得到终端IMSI标识后,向HLR中请求进行认证,并根据HLR下达的用户签约数据对终端进行鉴权,同时SGSN将终端的当前位置信息上传HLR。鉴权通过后,SGSN就会向终端返回“接受附着”消息。 
  (2)PDP(Packet Data Protocol)上下文激活。通过PDP上下文激活过程,用户获得相应的GGSN的鉴权许可,分配相应的IPv6地址,建立终端与基于GPRS的3G分组域之间的数据通道。 
  PDP激活过程由用户终端发起。终端首先向SGSN发起“激活PDP上下文请求”消息,消息中携带APN(服务访问点名称),服务质量等信息;SGSN根据消息中携带的APN向HLR中查寻相应的GGSN的地址,获得GGSN地址后,再向GGSN发送“创建PDP上下文请求”;GGSN可以通过本地/DHCP/RADIUS对终端进行签权并分配IPv6地址或者地址前缀,以及其他参数,如QoS参数等,并将鉴权结果以及各项参数携带在“响应创建PDP上下文请求”消息中,发送给SGSN,由SGSN再向终端发送“接受激活PDP上下文请求”消息,将各参数配置传递给用户终端,从而完成PDP激活过程。 
  这一过程中,与IPv6相关的功能主要集中在IPv6地址请求/分配上。首先,终端在“激活PDP上下文请求”消息中需要携带请求地址类型为IPv6的信息;其次,系统要能够分配IPv6地址。如果系统采用GGSN本地地址池分配IPv6地址方式,那么GGSN需要支持IPv6地址池设置与分配,如果采用DHCP服务器或者RADIUS服务器要进行地址分配,那么就需要DHCP,RADIUS服务器支持IPv6。 
  (3)业务访问。在PDP之后,从终端到3G系统分组域的IPv6应用数据通道已经打开。如果终端访问3G系统外的业务服务器,就需要保持3G系统分组域与外部网络直到业务服务器之间的转发路径通畅,即3G系统分组域边界网关需要具备访问IPv6外部网络的路由与转发能力。通常的IPv6 3G应用解决方案中,GGSN作为3G分组域的对外网关要求具备双栈能力。

注意:sms的发送过程是走的ril,mms是走的http. mms apn激活过程走的是data call流程。

Android MMS APN工作原理以及PDP知识摘要相关推荐

  1. android 版本更新原理,Android系统Recovery工作原理之使用update.zip升级过程分析(二)...

    Android系统Recovery工作原理之使用update.zip升级过程分析(二)---update.zip差分包问题的解决 在上一篇末尾提到的生成差分包时出现的问题,现已解决,由于最近比较忙,相 ...

  2. Android系统Recovery工作原理之使用update.zip升级过程分析(五)

    Android系统Recovery工作原理之使用update.zip升级过程分析(五)---update.zip包从上层进入Recovery服务文章开头我们就提到update.zip包来源有两种,一个 ...

  3. Android系统Recovery工作原理之使用update.zip升级过程分析(二)---u...

    2019独角兽企业重金招聘Python工程师标准>>>  Android系统Recovery工作原理之使用update.zip升级过程分析(二)---update.zip差分包问题的 ...

  4. chrome android远程调试工作原理

    注意⚠️:本文为个人学习原理所翻译的文章,文中介绍的方法还未实践验证,不保证有效可用.目前仅进行了原理学习,后续会补充实际操作过程中遇到的问题. chrome android远程调试工作原理 Chro ...

  5. Android App的工作原理

    Android App的工作原理 Android系统是基于liunx内核的,但是与传统的基于liunx的pc系统不同, 用户对Android app没有绝对的掌控权.pc系统中, 在应用程序的系统菜单 ...

  6. Android 动画的工作原理

    在android系统中动画分为两种分别是基础动画和属性动画.对于动画的工作原理主要涉及到的是基础动画和属性动画的实现. 本章主要分两大块:基础动画和属性动画 1.基础动画 对于基础动画的实现主要是嵌套 ...

  7. Android系统Recovery工作原理之使用update.zip升级过程分析(四)

    Android系统Recovery模式的工作原理在使用update.zip包升级时怎样从主系统(main system)重启进入Recovery模式,进入Recovery模式后怎样判断做何种操作,以及 ...

  8. Android中AMS工作原理,Android AMS启动详解

    启动 在Android系统启动流程中中我们提到过,AMS是在system_service中启动的, //frameworks/base/services/java/corri/android/serv ...

  9. Android系统Recovery工作原理之使用update.zip升级过程分析(一)

    这篇及以后的篇幅将通过分析update.zip包在具体Android系统升级的过程,来理解Android系统中Recovery模式服务的工作原理.我们先从update.zip包的制作开始,然后是And ...

最新文章

  1. linux java内存分析_Java内存分析利器MAT使用详解
  2. lua搭建ui_构建类魔兽UI插件的lua安全沙箱
  3. Schema中elementFormDefault=qualified所起的作用
  4. E24- please install the following Perl modules before executing ./mysql_install_db
  5. SpringCloud 入门教程(五): Ribbon实现客户端的负载均衡
  6. mysql的递归查询_比较两种mysql递归tree查询效率-mysql递归tree
  7. freemarker开发指南
  8. Python Selenium系列学习
  9. Javascript 日期校验完备全过程
  10. Mocha BSM产品亮点——SNMP Trap的支持
  11. 方舟生存进化mysql_基于MySQL 的 SQL 优化总结_卡盟,辅助
  12. C++开发坦克大战--补充(加入传送门)--附完整代码
  13. 安川机器人io对照表_安川机器人按键功能一览
  14. STL 格式解析--文本以及二进制格式
  15. html提示框延时消失,javascript实现延时显示提示框特效代码
  16. 【转载】SAP_ECC6.0_EHP4或SAP_ECC6.0_EHP5_基于Windows_Server_2008R2_和SQL_server_2008下的安装...
  17. 关于使用腾讯乐固加固,涉及的签名及其他问题
  18. PHP 笔试 + 面试题
  19. ffmpeg安装遇错:nasm/yasm not found or too old. Use --disable-x86asm for a crippled build.
  20. mac 双开应用的方法

热门文章

  1. 【前端学习】前端学习第十五天:JavaScript中的事件模型
  2. 使用c#封装海康SDK出现无法加载 DLL“..\bin\HCNetSDK.dll”: 找不到指定的模块
  3. C语言递归及经典例题详解
  4. 基于OpencV的轮廓填充算法在3D打印机中的应用
  5. 工程效率如何为研发赋能
  6. VGA及其支持的模式
  7. python计时器类
  8. 推荐一个好用的抠图软件
  9. R语言问题【已解决】读取CSV稳健出错:invalid multibyte string
  10. 模板生成word文档 By POI+Word书签功能