【Android架构Telephony篇】数据业务总览

12 篇文章 0 订阅
7 篇文章 0 订阅
  1. Android: 6.0  
  2. Desktop: Ubuntu 15.04  
  3. 更新:2017-04-27  

Android设备中完整的移动通讯系统构成:

(1)Hardware

这里提到的无线通信模组是一种支持TD-LTE/FDD-LTE/TD-SCDMA/WCDMA/EVDO/CDMA1X/GSM等等网络制式的通信模块,能够为用户提供高速的无线数据、互联网接入等业务,具备语音、分组数据、短信功能,彩信等功能。提供这些功能使用服务的就是联通/移动/电信等运营商,通过SIM卡注册到各自的网络中,付费使用。


(2)Kernel

内核中实现访问无线通信模组的数据通道,比如对于串口类模组就可以为/dev/ttyS0(/dev/ttyS1...),USB接口的为/dev/ttyUSB0(/dev/ttyUSB1...)等。

而要使用模组的网络功能,还必须实现网络功能的通信协议,比如常见的PPP(Point-to-Point Protocol):

[html]  view plain  copy
 print ?
  1. PPP  is  the  protocol used for establishing internet links over dial-up modems, DSL connections, and many other types of point-to-point links.  The  

为直观故,我们看下通过PPP建立网络连接的log:


最后一行返回status为0,说明网络建立成功。

同时,它也显示了本地IP、远程IP、DNS等网络信息。在Android拨号过程中,用到的两个重要文件是/data/connect和/etc/ppp/ip-up。

这时可以adb shell进入系统,看下网络:

[python]  view plain  copy
 print ?
  1. netcfg  

或:

[html]  view plain  copy
 print ?
  1. busybox ifconfig  


(3)Framework

该层的Telephony子系统完成无线通信模块所有功能的具体实现,同时为应用开发人员提供使用接口。

(4)App

作为App开发人员,调用Telephony的API,实现具体功能的App工用户使用。


Android的Telephony子系统也是非常复杂的,涉及很多方面。我们以数据业务为分析入口,从上到下走一遍框图中的流程。


http://blog.csdn.net/u013686019/article/details/49719897

Telephony的Overview见:

【Android架构Telephony篇】数据业务(1)总览

一、Telephony整体流程

Telephony执行的完整流程如下:


下面自上而下,只关注主干,分层看下代码走向。


二、Telephony数据业务的RILJ层

1、App层

用户点击系统【设置】进行开启/关闭数据业务,调用:

[java]  view plain  copy
 print ?
  1. DataUsageSummary.java (packages\apps\settings\src\com\android\settings)  
  2. private void setMobileDataEnabled(int subId, boolean enabled) {  
  3.     mTelephonyManager.setDataEnabled(subId, enabled);  
  4. }  

TelephonyManager作为"phone"系统服务的管理类,其获取方式可以:

[java]  view plain  copy
 print ?
  1. DataUsageSummary#onCreate()  
  2. -->mTelephonyManager = TelephonyManager.from(context);  
  3.   
  4. TelephonyManager.java (frameworks\base\telephony\java\android\telephony)  
  5. public static TelephonyManager from(Context context) {  
  6.     return (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);  
  7. }  


在上图中,把"phone"系统服务获取放在了frameworks层,这是因为在frameworks中可以越过Manager类直接获取服务,如:

[java]  view plain  copy
 print ?
  1. TelephonyManager.java (frameworks\base\telephony\java\android\telephony)  
  2. private ITelephony getITelephony() {  
  3.     return ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));  
  4. }  
  5.   
  6. public void setDataEnabled(int subId, boolean enable) {  
  7.     ITelephony telephony = getITelephony();  
  8.     telephony.setDataEnabled(subId, enable);  
  9. }  

Telephony提供的操作无线模组的方法可以通过ITelephony.aidl文件查看:
[java]  view plain  copy
 print ?
  1. frameworks/base/telephony/java/com/android/internal/telephony/ITelephony.aidl  


2、Framework层

(1)"phone"系统服务注册

系统服务绝大部分都在frameworks/base/services/java/com/android/server/SystemServer.java文件中统一注册,但TELEPHONY_SERVICE("phone")服务很是另类,其注册流程:

[java]  view plain  copy
 print ?
  1. PhoneApp.java (packages\services\telephony\src\com\android\phone)  
  2. public class PhoneApp extends Application {}  
  3. PhoneApp#onCreate()  
  4. -->PhoneGlobals#onCreate()  
  5. ---->PhoneInterfaceManager#init()  
  6. ------>PhoneInterfaceManager#publish()  
  7. -------->PhoneInterfaceManager#ServiceManager.addService("phone"this);  


adb shell进去系统,通过service命令可以查看系统注册的所有服务:

[java]  view plain  copy
 print ?
  1. # service list                                               
  2. Found 102 services:  
  3. 1   phone: [com.android.internal.telephony.ITelephony]  

(2) 继续数据业务流程

PhoneInterfaceManager是"phone"服务实现方,对于数据开启/关闭:

[java]  view plain  copy
 print ?
  1. PhoneInterfaceManager.java (packages\services\telephony\src\com\android\phone)  
  2. /** 
  3.  * Set mobile data enabled 
  4.  * Used by the user through settings etc to turn on/off mobile data 
  5.  */  
  6. @Override  
  7. public void setDataEnabled(int subId, boolean enable) {  
  8.     enforceModifyPermission(); -->a  
  9.     int phoneId = mSubscriptionController.getPhoneId(subId); -->b  
  10.     Phone phone = PhoneFactory.getPhone(phoneId);  
  11.     phone.setDataEnabled(enable);  
  12. }  

这里的Phone是一个interface。在【Android架构Telephony篇】数据业务(1)总览提到,无线通信有TD-LTE/FDD-LTE/TD-SCDMA/WCDMA/EVDO/CDMA1X/GSM等等很多的网络制式,不同模块可以支持其中的一种或多种。它们之间的区别最简单的例子,比如常说的电信卡、联通卡等等。从软件层面进行抽象就是:



Phone的创建

[java]  view plain  copy
 print ?
  1. PhoneFactory.java (frameworks\opt\telephony\src\java\com\android\internal\telephony)  
  2. public static void makeDefaultPhone(Context context) {  
  3.     PhoneBase phone = null;  
  4.     int phoneType = TelephonyManager.getPhoneType(networkModes[i]);  
  5.     if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {  
  6.         phone = new GSMPhone(context,  
  7.                 sCommandsInterfaces[i], sPhoneNotifier, i);  
  8.     } else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {  
  9.         phone = new CDMALTEPhone(context,  
  10.                 sCommandsInterfaces[i], sPhoneNotifier, i);  
  11.     }  
  12. }  

这里就根据type创建不同的Phone,我们以GSMPhone为例,setDataEnabled()调用的就是:

[java]  view plain  copy
 print ?
  1. GSMPhone.java (frameworks\opt\telephony\src\java\com\android\internal\telephony\gsm)  
  2. public void setDataEnabled(boolean enable) {  
  3.     mDcTracker.setDataEnabled(enable);  
  4. }  

mDcTracker是一个Handler,

[java]  view plain  copy
 print ?
  1. DcTrackerBase.java (frameworks\opt\telephony\src\java\com\android\internal\telephony\dataconnection)  
  2. public void setDataEnabled(boolean enable) {  
  3.     Message msg = obtainMessage(DctConstants.CMD_SET_USER_DATA_ENABLE);  
  4.     msg.arg1 = enable ? 1 : 0;  
  5.     sendMessage(msg);  
  6. }  
  7. public void handleMessage(Message msg) {  
  8.     switch (msg.what) {  
  9.     case DctConstants.CMD_SET_USER_DATA_ENABLE: {  
  10.         final boolean enabled = (msg.arg1 == DctConstants.ENABLED) ? true : false;  
  11.         onSetUserDataEnabled(enabled);  
  12.         break;  
  13.     }  
  14. }  
  15.   
  16. DcTrackerBase#onSetUserDataEnabled()  
  17. -->DcTrackerBase#onTrySetupData()  

DcTrackerBase发送CMD_SET_USER_DATA_ENABLE信息,并自己处理,最终调用到onTrySetupData(),实现onTrySetupData()的地方:

[java]  view plain  copy
 print ?
  1. DcTracker.java (opt\telephony\src\java\com\android\internal\telephony\dataconnection)  
  2. protected boolean onTrySetupData(String reason) {  
  3.     setupDataOnConnectableApns(reason);  
  4.     return true;  
  5. }  

setupDataOnConnectableApns()顾名思义就是使用可用的APN建立数据连接,之后:
[java]  view plain  copy
 print ?
  1. DcTracker.java (opt\telephony\src\java\com\android\internal\telephony\dataconnection)  
  2. setupDataOnConnectableApns(reason, RetryFailures.ALWAYS);  
  3. -->trySetupData(apnContext, waitingApns);  
  4. ---->setupData(apnContext, radioTech);  
  5.   
  6. private boolean setupData(ApnContext apnContext, int radioTech) {  
  7.     // 用于连接DcTracker和DataConnection  
  8.     DcAsyncChannel dcac = null;  
  9.   
  10.     if (dcac == null) {  
  11.         // 获取/创建DcAsyncChannel对象  
  12.     }  
  13.       
  14.     // 更新apnContext  
  15.     apnContext.setDataConnectionAc(dcac);  
  16.     apnContext.setApnSetting(apnSetting);  
  17.     apnContext.setState(DctConstants.State.CONNECTING);  
  18.     mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());  
  19.   
  20.     // 拨号成功后发送EVENT_DATA_SETUP_COMPLETE信息  
  21.     Message msg = obtainMessage();  
  22.     msg.what = DctConstants.EVENT_DATA_SETUP_COMPLETE;  
  23.     msg.obj = new Pair<ApnContext, Integer>(apnContext, generation);  
  24.     dcac.bringUp(apnContext, getInitialMaxRetry(), profileId, radioTech,  
  25.             mAutoAttachOnCreation.get(), msg, generation);  
  26.     return true;  
  27. }  

调用DcAsyncChannel的bringUp(),向DataConnection发送建立连接消息EVENT_CONNECT:

[java]  view plain  copy
 print ?
  1. DcAsyncChannel.java (opt\telephony\src\java\com\android\internal\telephony\dataconnection)  
  2. /** 
  3.  * Bring up a connection to the apn and return an AsyncResult in onCompletedMsg. 
  4.  * Used for cellular networks that use Acesss Point Names (APN) such 
  5.  * as GSM networks. 
  6.  */  
  7. public void bringUp(ApnContext apnContext, int initialMaxRetry, int profileId,  
  8.         int rilRadioTechnology, boolean retryWhenSSChange, Message onCompletedMsg,  
  9.         int connectionGeneration) {  
  10.     sendMessage(DataConnection.EVENT_CONNECT,  
  11.                 new ConnectionParams(apnContext, initialMaxRetry, profileId,  
  12.                         rilRadioTechnology, retryWhenSSChange, onCompletedMsg,  
  13.                         connectionGeneration));  
  14. }  

DataConnection处理EVENT_CONNECT:

[java]  view plain  copy
 print ?
  1. DataConnection.java (opt\telephony\src\java\com\android\internal\telephony\dataconnection)  
  2. private class DcInactiveState extends State { -->a  
  3.     public boolean processMessage(Message msg) {  
  4.         case EVENT_CONNECT:  
  5.             ConnectionParams cp = (ConnectionParams) msg.obj;  
  6.             if (initConnection(cp)) {<span style="font-family:Courier New;"> --></span>b  
  7.                 onConnect(mConnectionParams); -->c  
  8.                 transitionTo(mActivatingState);  
  9.             } else {  
  10.                 log("DcInactiveState: msg.what=EVENT_CONNECT initConnection failed");  
  11.                 notifyConnectCompleted(cp, DcFailCause.UNACCEPTABLE_NETWORK_PARAMETER,  
  12.                         false);  
  13.             }  
  14.             retVal = HANDLED;  
  15.             break;  
  16.     }  
  17. }  
a,  DataConnection 是一个状态机,其初始状态:

[java]  view plain  copy
 print ?
  1. private DcInactiveState mInactiveState = new DcInactiveState();  
  2. private DataConnection() {  
  3.     setInitialState(mInactiveState);  
  4. }  
所以这里调用DcInactiveState类的processMessage()处理EVENT_CONNECT信息。

b, 检测参数合法性

c, 调用onConnect()启动连接建立

[java]  view plain  copy
 print ?
  1. /** 
  2.  * Begin setting up a data connection, calls setupDataCall 
  3.  * and the ConnectionParams will be returned with the 
  4.  * EVENT_SETUP_DATA_CONNECTION_DONE AsyncResul.userObj. 
  5.  */  
  6. private void onConnect(ConnectionParams cp) {  
  7.   
  8.     // msg.obj will be returned in AsyncResult.userObj;  
  9.     Message msg = obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE, cp);  
  10.     msg.obj = cp;  
  11.   
  12.     mPhone.mCi.setupDataCall(  
  13.             Integer.toString(cp.mRilRat + 2),  
  14.             Integer.toString(cp.mProfileId),  
  15.             mApnSetting.apn, mApnSetting.user, mApnSetting.password,  
  16.             Integer.toString(authType),  
  17.             protocol, msg);  
  18. }  

mCi是一个CommandsInterface,实现它的是RIL:

[java]  view plain  copy
 print ?
  1. RIL.java (opt\telephony\src\java\com\android\internal\telephony)  
  2. public final class RIL extends BaseCommands implements CommandsInterface {  
  3. }  

这里,就来到了开篇流程图中的“RILJ”,在继续下去之前,稍微提下Android中 本地socket通信

(3)socket进程间通信

Linux中的socket除了可以用于不同机器之间的网络通信,还可以用于同一台机器的进程间通信。以Telephony为例,RILJ的java进程和RILC的c守护进程之间就是通过"/dev/socket/rild"这个socket进行通信的。

a, socket建立

[java]  view plain  copy
 print ?
  1. RIL.java (opt\telephony\src\java\com\android\internal\telephony)  
  2. LocalSocket mSocket;  
  3. String rilSocket = "rild";  
  4. s = new LocalSocket();  
  5. l = new LocalSocketAddress(rilSocket, LocalSocketAddress.Namespace.RESERVED);  
  6. s.connect(l);  
  7.   
  8. mSocket = s;  


b, 数据发送

[java]  view plain  copy
 print ?
  1. RIL.java (opt\telephony\src\java\com\android\internal\telephony)  
  2. class RILSender extends Handler implements Runnable {  
  3. @Override public void handleMessage(Message msg) {  
  4.     switch (msg.what) {  
  5.     case EVENT_SEND:  
  6.         try {  
  7.             LocalSocket s;  
  8.             s = mSocket;  
  9.   
  10.             synchronized (mRequestList) {  
  11.                 mRequestList.append(rr.mSerial, rr);  
  12.             }  
  13.   
  14.             byte[] data;  
  15.   
  16.             data = rr.mParcel.marshall();  
  17.             rr.mParcel.recycle();  
  18.             rr.mParcel = null;  
  19.   
  20.             // parcel length in big endian  
  21.             dataLength[0] = dataLength[1] = 0;  
  22.             dataLength[2] = (byte)((data.length >> 8) & 0xff);  
  23.             dataLength[3] = (byte)((data.length) & 0xff);  
  24.   
  25.             s.getOutputStream().write(dataLength);  
  26.             s.getOutputStream().write(data);  
  27.         }  
  28.     }  
  29. }  

c, 数据接收

[java]  view plain  copy
 print ?
  1. RIL.java (opt\telephony\src\java\com\android\internal\telephony)  
  2. class RILReceiver implements Runnable {  
  3.     try {  
  4.         InputStream is = mSocket.getInputStream();  
  5.         for (;;) {  
  6.             Parcel p;  
  7.             length = readRilMessage(is, buffer);  
  8.             if (length < 0) {  
  9.                 // End-of-stream reached  
  10.                 break;  
  11.             }  
  12.   
  13.             p = Parcel.obtain();  
  14.             p.unmarshall(buffer, 0, length);  
  15.             p.setDataPosition(0);  
  16.             processResponse(p); // 数据处理  
  17.             p.recycle();  
  18.         }  
  19.     }  
  20. }  

有了这个知识,RILJ就容易理解了。

(4)RILJ

[java]  view plain  copy
 print ?
  1. RIL.java (opt\telephony\src\java\com\android\internal\telephony)  
  2. @Override  
  3. public void  setupDataCall(String radioTechnology, String profile, String apn,  
  4.         String user, String password, String authType, String protocol,  
  5.         Message result) {  
  6.     RILRequest rr  
  7.             = RILRequest.obtain(RIL_REQUEST_SETUP_DATA_CALL, result);  
  8.   
  9.     rr.mParcel.writeInt(7);  
  10.   
  11.     rr.mParcel.writeString(radioTechnology);  
  12.     rr.mParcel.writeString(profile);  
  13.     rr.mParcel.writeString(apn);  
  14.     rr.mParcel.writeString(user);  
  15.     rr.mParcel.writeString(password);  
  16.     rr.mParcel.writeString(authType);  
  17.     rr.mParcel.writeString(protocol);  
  18.   
  19.     send(rr);  
  20. }  
  21.   
  22. private void send(RILRequest rr) {  
  23.     Message msg;  
  24.   
  25.     if (mSocket == null) {  
  26.         rr.onError(RADIO_NOT_AVAILABLE, null);  
  27.         rr.release();  
  28.         return;  
  29.     }  
  30.   
  31.     msg = mSender.obtainMessage(EVENT_SEND, rr);  
  32.   
  33.     acquireWakeLock();  
  34.   
  35.     msg.sendToTarget();  
  36. }  

无需解释。


【Android架构Telephony篇】数据业务(3)RILC




http://blog.csdn.net/u013686019/article/details/53580878

三、Telephony数据业务的RILC层

现在,建立移动数据业务的任务通过socket传递给C/C++的RIL进行处理了:

[cpp]  view plain  copy
 print ?
  1. hardware\ril\rild\rild.c:  
  2. int main(int argc, char **argv)  
  3. {  
  4.     char libPath[PROPERTY_VALUE_MAX];  
  5.       
  6.     /**启动rild并解析/init.rc传进来的参数: 
  7.      * rild -l /system/lib/libreference-ril.so -- -d /dev/mux2 
  8.      */  
  9.     for (i = 1; i < argc ;) {  
  10.         if (0 == strcmp(argv[i], "-l") && (argc - i > 1)) {  
  11.             rilLibPath = argv[i + 1]; // ril库的路径,即"/system/lib/libreference-ril.so"  
  12.             i += 2;  
  13.         } else if (0 == strcmp(argv[i], "--")) {  
  14.             i++;  
  15.             hasLibArgs = 1;  
  16.             break;  
  17.         } else {  
  18.             usage(argv[0]);  
  19.         }  
  20.     }  
  21.   
  22.     /** 启动/system/bin/muxd,生成/dev/mux2节点 */  
  23.     startmux(bpID);  
  24.   
  25.     /** 加载传进来的/system/lib/libreference-ril.so库*/  
  26.     dlHandle = dlopen(rilLibPath, RTLD_NOW);  
  27.   
  28.     if (dlHandle == NULL) {  
  29.         RLOGE("dlopen failed: %s", dlerror());  
  30.         exit(-1);  
  31.     }  
  32.   
  33.     /** 事件监听 */  
  34.     RIL_startEventLoop();  
  35.   
  36.     rilInit = (const RIL_RadioFunctions *(*)(const struct RIL_Env *, intchar **))dlsym(dlHandle, "RIL_Init");  
  37.   
  38.     if (rilInit == NULL) {  
  39.         RLOGE("RIL_Init not defined or exported in %s\n", rilLibPath);  
  40.         exit(-1);  
  41.     }  
  42.   
  43.     /**注册事件回调函数 
  44.      *static struct RIL_Env s_rilEnv = { 
  45.      *  RIL_onRequestComplete, 
  46.      *  RIL_onUnsolicitedResponse, 
  47.      *  RIL_requestTimedCallback 
  48.      *}; 
  49.      */  
  50.     funcs = rilInit(&s_rilEnv, argc, rilArgv);  
  51.   
  52.     RIL_register(funcs);  
  53. done:  
  54.     while(1) {  
  55.         sleep(0x00ffffff);  
  56.     }  
  57. }  

rild用来对RIL进行管理。对于不同的Modem,尤其不同无线通信技术(GSM、CDMA)之间,其差别是很大的;就算是同种技术的Modem,不同厂商也有区别。所以管理部分处理它们共通的业务逻辑,而把具体的实现交给xxxril.so。管理部分涉及文件:hardware\ril\libril\ril.cpp、hardware\ril\libril\ril_event.cpp,本文不对该部分进行分析。


/system/lib/libreference-ril.so库处理AT指令相关操作,/dev/mux2用作数据通道。我们知道,Modem和CPU之间是通过串口连接的,为了使AT指令和数据分开管理,系统对串口进行了复用。原理和实现参见:hardware/ril/gsm0710muxd/src/gsm0710muxd.c。

回到数据业务建立上面。在RIL的具体实现上,每一个操作,比如短信、电话、查询信号强度等都有独有的Request,且RILC/C++和RILJava定义一致。建立数据连接的Request是RIL_REQUEST_SETUP_DATA_CALL:

[java]  view plain  copy
 print ?
  1. frameworks\opt\telephony\src\java\com\android\internal\telephony\RIL.java  
  2. RILRequest rr = RILRequest.obtain(RIL_REQUEST_SETUP_DATA_CALL, result);  

响应该request的地方是:

[cpp]  view plain  copy
 print ?
  1. hardware\ril\reference-ril\reference-ril.c  
  2. /** 
  3.  * Call from RIL to us to make a RIL_REQUEST 
  4.  */  
  5. static void onRequest (int request, void *data, size_t datalen, RIL_Token t)  
  6. {  
  7.     switch (request) {  
  8.     case RIL_REQUEST_SETUP_DATA_CALL:  
  9.         requestSetupDataCall(data, datalen, t);  
  10.         break;  
  11.     }  
  12. }  
  13.   
  14. static void requestSetupDataCall(void *data, size_t datalen, RIL_Token t)  
  15. {  
  16.     char value[PROPERTY_VALUE_MAX] = "";  
  17.     char dns1[64]="";  
  18.     char dns2[64]="";  
  19.     char *cmd;  
  20.     int err,i,fd;  
  21.   
  22.     char *response[3] = { "ppp0""IP", ip_address };  
  23.     RIL_Data_Call_Response_v6 response_v6;  
  24.     int mypppstatus;  
  25.     char strTemp[32];  
  26.     ATResponse *p_response = NULL;  
  27.     char *dialup = NULL;  
  28.     int cid = 1;  
  29.     int channel = 0;  
  30.     char dev_path[32];  
  31.     char gateway[PROPERTY_VALUE_MAX] = "";  
  32.   
  33.     const char* radioTechnology = ((const char**)data)[0];  
  34.     const char* profile = ((const char**)data)[1];  
  35.     const char* apn = ((const char**)data)[2];  
  36.     const char* user = ((const char**)data)[3];  
  37.     const char* password = ((const char**)data)[4];  
  38.     const char* authType = ((const char**)data)[5];  
  39.     char *auth_option;  
  40.     memset(ip_address,0,32);  
  41.     LOGD("radioTechnology:%s", radioTechnology);  
  42.     LOGD("profile:%s", profile);  
  43.     LOGD("apn:%s", apn);  
  44.     LOGD("user:%s", user);  
  45.     LOGD("password:%s", password);  
  46.     LOGD("authType:%s", authType);  
  47.   
  48.     /** 
  49.      * 数据业务建立的方式,依据不同Modem而有所不同 
  50.      */  
  51.     asprintf(&cmd, "/etc/ppp/call-pppd "  
  52.             "\"%s 115200\" " // $1  
  53.             "\"novj novjccomp noccp ipcp-accept-local ipcp-accept-remote\" " // $2  
  54.             "\"%s\" \"%s\" " // $3  $4  
  55.             "\"%s\" \"%s\" &"// $5  $6  
  56.             s_pppChannel, user, password, conn_script, disconn_script);  
  57.     ret = system(cmd);  
  58.     RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);  
  59.     at_response_free(p_response);  
  60. }  

据业务建立的方式,依据不同Modem而有所不同,对于PPP方式,Android下的一个实现是通过/etc/ppp/call-pppd脚本进行:

[python]  view plain  copy
 print ?
  1. /etc/ppp/call-pppd  
  2. #!/system/bin/sh  
  3. # An unforunate wrapper script   
  4. # so that the exit code of pppd may be retrieved  
  5.   
  6. #PPPD_PID=""  
  7. PPPD_EXIT=""  
  8.   
  9. /system/bin/setprop "net.gprs.ppp-exit" ""  
  10.   
  11. /system/bin/pppd $1 debug defaultroute noauth nodetach nocrtscts $2 noipdefault usepeerdns user "$3" password "$4" connect "$5" disconnect "$6"  
  12.   
  13. PPPD_EXIT=$?  
  14. #PPPD_PID=$!  
  15.   
  16. /system/bin/setprop "net.gprs.ppp-exit" "$PPPD_EXIT"  

call-pppd脚本需要我们传进来6个参数,比如:
[cpp]  view plain  copy
 print ?
  1. asprintf(&cmd, "/etc/ppp/call-pppd "  
  2.     "\"%s 115200\" " // $1  
  3.     "\"novj novjccomp noccp ipcp-accept-local ipcp-accept-remote\" " // $2  
  4.     "\"%s\" \"%s\" " // $3  $4  
  5.     "\"%s\" \"%s\" &"// $5  $6  
  6.     s_pppChannel, user, password, conn_script, disconn_script);  
  7. ret = system(cmd);  

system(const char *command)函数用来执行call-pppd脚本,log:



至此,数据业务建立完成,通过ifconfig命令查看,生成由ppp设备节点。



转自 http://blog.csdn.net/u013686019/article/details/53580878 

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值