Android网络相关---上网流程

网络应用,对于用户来说,主要是搜索,浏览网页,发email,发mms。对于android来说这些应用涉及到的一些中间过程,主要涉及到webkit,wap,smtp等协议,然后是socket通信,然后就是linux内核的tcpip协议栈,及ppp协议,最后再是ttyS0之类的设备接口,最后由modem发送数据。另外手机的网络接口可能不是modem,有可能是网卡或者wifi,那么android中也有相应的接口可以添加。

不过有线网卡,目前用的比较少,毕竟手机或平板电脑上很少会用到体积大的网口。

 

先在总体上看一下网络流程

这里主要讨论modem的形式。

 

 应用程序->触发网络连接(或已连接)->android本地的jni socket函数->内核中的BSD socket?->tcp/ip->ppp->/dev/ttySx(modem的数据口)。

 在触发的网络连接,如果没有连接,则会时行拨号,拨号有一些初始化at命令,及一个拨号命令,atd*99***1#,这些实现是RIL.java与相 对应的ril.cpp文件中完成。拨号成功后,就进行ppp协商过程,ppp协商成功后,移动网络会给终端分配ip地址,网关和dns地址。然后网络连接 就成功了。之后就就是发送上层应用程序数据。

 

在我们的应用程序中,触发了上网需求,系统会去检测网络是否连接,当然对于有多种接口,会轮询,看哪一个连接可用(这里应该是否有优先级,先有线,然后wifi,最后是modem,毕竟modem的费用是最高)

 

  在ppp拨号之前,所有的实现都包含在PhoneService中,即在frameworks/base/telephony/java/com/android/internal/telephony/目录下,

  毕竟拨号这个动作还是属于电话范畴。

  首先在PhoneApp.java中:onCreate          

[java] view plain copy
  1. PhoneFactory.makeDefaultPhones(this); //生成一个基本的电话服务形式  

  在PhoneFactory.java中的:public static void makeDefaultPhone(Context context)中

[java] view plain copy
  1. int phoneType = getPhoneType(networkMode);  
  2.              if (phoneType == Phone.PHONE_TYPE_GSM) {  
  3.                  sProxyPhone = new PhoneProxy(new GSMPhone(context,  
  4.                          sCommandsInterface, sPhoneNotifier));  
  5.                  Log.i(LOG_TAG, "Creating GSMPhone");  
  6.              } else if (phoneType == Phone.PHONE_TYPE_CDMA) {  
  7.                  sProxyPhone = new PhoneProxy(new CDMAPhone(context,  
  8.                          sCommandsInterface, sPhoneNotifier));  
  9.                  Log.i(LOG_TAG, "Creating CDMAPhone");  
  10.              }  
  11.             //创建PhoneProxy,则PhoneProxy中,又创建GSMPhone,如果网络是cdma,那么则创建CDMAPhone。这里不讨论cdma制式的网络.<span style="font-family: Arial, Verdana, sans-serif; white-space: normal; background-color: rgb(255, 255, 255); ">  </span>  

   在GSMPhone.java的,构造函数中,

[java] view plain copy
  1. mDataConnection = new GsmDataConnectionTracker (this);  

   在GsmDataConnectionTracker.java中,GsmDataConnectionTracker类是继承于DataConnectionTracker。在GsmDataConnectionTracker构造函数调用了createAllPdpList();函数在   GsmDataConnectionTracker.java中。如下:               

[java] view plain copy
  1. private void createAllPdpList() {  
  2.                     pdpList = new ArrayList<DataConnection>();  
  3.                     DataConnection pdp;  
  4.    
  5.                     for (int i = 0; i < PDP_CONNECTION_POOL_SIZE; i++) {  
  6.                         pdp = new PdpConnection(mGsmPhone);  
  7.                         pdpList.add(pdp);  
  8.                      }  
  9.                 }  
  10.                 //创建了PDP_CONNECTION_POOL_SIZE个PdpConnection(PDP_CONNECTION_POOL_SIZE等于1)  

     在应用程序触发网络发送数据,如触发了onApnChanged,onRoamingOff,onRoamingOn等函数,或者处理消息时,会调用trySetupData函数

     对于trySetupData函数,刚会调用setupData(reason);进行数据连接。       

[java] view plain copy
  1. private boolean setupData(String reason) {  
  2.                    ApnSetting apn;  
  3.                    PdpConnection pdp;  
  4.   
  5.                    apn = getNextApn();  
  6.                    if (apn == nullreturn false;  
  7.                    pdp = findFreePdp();  
  8.                    if (pdp == null) {  
  9.                        if (DBG) log("setupData: No free PdpConnection found!");  
  10.                        return false;  
  11.                    }  
  12.                    mActiveApn = apn;  
  13.                    mActivePdp = pdp;  
  14.   
  15.                    Message msg = obtainMessage();  
  16.                    msg.what = EVENT_DATA_SETUP_COMPLETE;  
  17.                    msg.obj = reason;  
  18.                    pdp.connect(apn, msg);  
  19.   
  20.                    setState(State.INITING);  
  21.                    phone.notifyDataConnection(reason);  
  22.                    return true;  
  23.                }  
  24.                //调用了pdp.connect(apn, msg)。时行拨号,即应该是往RIL.java层发送拨号请求了。<span style="font-family: Arial, Verdana, sans-serif; white-space: normal; background-color: rgb(255, 255, 255); ">        </span>  

    接下来,看PdpConnection.java文件,继承于DataConnection

        此文件实现了connect,disconnect等方法。

        在connect,setupDataCall接口方法           

[java] view plain copy
  1. phone.mCM.setupDataCall(Integer.toString(RILConstants.SETUP_DATA_TECH_GSM),  
  2.                Integer.toString(RILConstants.DATA_PROFILE_DEFAULT), apn.apn, apn.user,  
  3.                apn.password, Integer.toString(authType),  
  4.                obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE));  

        mCM的类型是CommandsInterface,即是一些电话服务相碰的通用接口。这个接口的实现,就是RIL类,下面看RIL.java

       

  RIL.java完成android电话服务与modem操作的一转换功能。即把一些电话服务转换为实现的at命令,发送到modem

          在RIL类的中setupDataCall方法,实现如下:         

[java] view plain copy
  1. public void  
  2.        setupDataCall(String radioTechnology, String profile, String apn,  
  3.                String user, String password, String authType, Message result) {  
  4.            RILRequest rr  
  5.                    = RILRequest.obtain(RIL_REQUEST_SETUP_DATA_CALL, result);  
  6.   
  7.            rr.mp.writeInt(6);  
  8.   
  9.            rr.mp.writeString(radioTechnology);  
  10.            rr.mp.writeString(profile);  
  11.            rr.mp.writeString(apn);  
  12.            rr.mp.writeString(user);  
  13.            rr.mp.writeString(password);  
  14.            rr.mp.writeString(authType);  
  15.   
  16.            if (RILJ_LOGD) riljLog(rr.serialString() + "> "  
  17.                    + requestToString(rr.mRequest) + " " + radioTechnology + " "  
  18.                    + profile + " " + apn + " " + user + " "  
  19.                    + password + " " + authType);  
  20.   
  21.            send(rr);  
  22.        }  

        这个是通过socket方式给ril.cpp发送相关请求,引处发送RIL_REQUEST_SETUP_DATA_CALL请求,那么在ril.cpp 就会相应的完成话往modem通过串口发送ATD*99***1#命令。最后回返at命令返回结果,成功的话,就会返回CONNECT OK,这时ril.cpp就会往RIL.java发送此命令成功的响应。在RIL.java中的run函数的循环中调用processResponse方 法进行解析相关的响应。       

[cpp] view plain copy
  1. processResponse()->processSolicited ()  
  2. >case RIL_REQUEST_SETUP_DATA_CALL: ret =  responseStrings(p); break;  

再通过rr.mResult.sendToTarget(),把返回结果送到上一层模块中。

       

        此时,系统会调用ppp拨号程序ppp的拨号源代码在external/ppp目录下。

        在Android1.6版本之前,系统封装了调用pppd的代码,在frameworks/base/telephony/java/com/android/internal/telephony/PppLink.java中。

        但之后就没有了,网上的介绍说是用了高通的方案,把pppd与系统的进程的通信通过了内存共享的方式来实现,因此在代码中就去掉了调用pppd的java代码。

       

        如何共享?这是个问题。不过应该是系统的事了。

        那么自己要手动进行pppd拨号了。

        什么时候拨号?这个是关键。gprs毕竟是有流量。大家都比较喜欢按需拨号,相当于智能拨号了。ppp已经提供了这个功能,加相应的参数即可。

       

        不过在新的android版本中,已经ppp代码进行了简化,没有chat.c文件,那自然没得有chat命令,也就无法用pppd call xxx这个命令。如果想用chat那么就要自己移植ppp程序。

你可能感兴趣的:(Android网络相关---上网流程)