转自 https://blog.csdn.net/u013686019/article/details/53580878
三、Telephony数据业务的RILC层
现在,建立移动数据业务的任务通过socket传递给C/C++的RIL进行处理了:
-
hardware\ril\rild\rild.c:
-
int main(int argc, char **argv)
-
{
-
char libPath[PROPERTY_VALUE_MAX];
-
/**启动rild并解析/init.rc传进来的参数:
-
* rild -l /system/lib/libreference-ril.so -- -d /dev/mux2
-
*/
-
for (i = 1; i < argc ;) {
-
if (0 == strcmp(argv[i], "-l") && (argc - i > 1)) {
-
rilLibPath = argv[i + 1]; // ril库的路径,即"/system/lib/libreference-ril.so"
-
i += 2;
-
} else if (0 == strcmp(argv[i], "--")) {
-
i++;
-
hasLibArgs = 1;
-
break;
-
} else {
-
usage(argv[0]);
-
}
-
}
-
/** 启动/system/bin/muxd,生成/dev/mux2节点 */
-
startmux(bpID);
-
/** 加载传进来的/system/lib/libreference-ril.so库*/
-
dlHandle = dlopen(rilLibPath, RTLD_NOW);
-
if (dlHandle == NULL) {
-
RLOGE("dlopen failed: %s", dlerror());
-
exit(-1);
-
}
-
/** 事件监听 */
-
RIL_startEventLoop();
-
rilInit = (const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **))dlsym(dlHandle, "RIL_Init");
-
if (rilInit == NULL) {
-
RLOGE("RIL_Init not defined or exported in %s\n", rilLibPath);
-
exit(-1);
-
}
-
/**注册事件回调函数
-
*static struct RIL_Env s_rilEnv = {
-
* RIL_onRequestComplete,
-
* RIL_onUnsolicitedResponse,
-
* RIL_requestTimedCallback
-
*};
-
*/
-
funcs = rilInit(&s_rilEnv, argc, rilArgv);
-
RIL_register(funcs);
-
done:
-
while(1) {
-
sleep(0x00ffffff);
-
}
-
}
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:
-
frameworks\opt\telephony\src\java\com\android\internal\telephony\RIL.java
-
RILRequest rr = RILRequest.obtain(RIL_REQUEST_SETUP_DATA_CALL, result);
响应该request的地方是:
-
hardware\ril\reference-ril\reference-ril.c
-
/**
-
* Call from RIL to us to make a RIL_REQUEST
-
*/
-
static void onRequest (int request, void *data, size_t datalen, RIL_Token t)
-
{
-
switch (request) {
-
case RIL_REQUEST_SETUP_DATA_CALL:
-
requestSetupDataCall(data, datalen, t);
-
break;
-
}
-
}
-
static void requestSetupDataCall(void *data, size_t datalen, RIL_Token t)
-
{
-
char value[PROPERTY_VALUE_MAX] = "";
-
char dns1[64]="";
-
char dns2[64]="";
-
char *cmd;
-
int err,i,fd;
-
char *response[3] = { "ppp0", "IP", ip_address };
-
RIL_Data_Call_Response_v6 response_v6;
-
int mypppstatus;
-
char strTemp[32];
-
ATResponse *p_response = NULL;
-
char *dialup = NULL;
-
int cid = 1;
-
int channel = 0;
-
char dev_path[32];
-
char gateway[PROPERTY_VALUE_MAX] = "";
-
const char* radioTechnology = ((const char**)data)[0];
-
const char* profile = ((const char**)data)[1];
-
const char* apn = ((const char**)data)[2];
-
const char* user = ((const char**)data)[3];
-
const char* password = ((const char**)data)[4];
-
const char* authType = ((const char**)data)[5];
-
char *auth_option;
-
memset(ip_address,0,32);
-
LOGD("radioTechnology:%s", radioTechnology);
-
LOGD("profile:%s", profile);
-
LOGD("apn:%s", apn);
-
LOGD("user:%s", user);
-
LOGD("password:%s", password);
-
LOGD("authType:%s", authType);
-
/**
-
* 数据业务建立的方式,依据不同Modem而有所不同
-
*/
-
asprintf(&cmd, "/etc/ppp/call-pppd "
-
"\"%s 115200\" " // $1
-
"\"novj novjccomp noccp ipcp-accept-local ipcp-accept-remote\" " // $2
-
"\"%s\" \"%s\" " // $3 $4
-
"\"%s\" \"%s\" &", // $5 $6
-
s_pppChannel, user, password, conn_script, disconn_script);
-
ret = system(cmd);
-
RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
-
at_response_free(p_response);
-
}
据业务建立的方式,依据不同Modem而有所不同,对于PPP方式,Android下的一个实现是通过/etc/ppp/call-pppd脚本进行:
-
/etc/ppp/call-pppd
-
#!/system/bin/sh
-
# An unforunate wrapper script
-
# so that the exit code of pppd may be retrieved
-
#PPPD_PID=""
-
PPPD_EXIT=""
-
/system/bin/setprop "net.gprs.ppp-exit" ""
-
/system/bin/pppd $1 debug defaultroute noauth nodetach nocrtscts $2 noipdefault usepeerdns user "$3" password "$4" connect "$5" disconnect "$6"
-
PPPD_EXIT=$?
-
#PPPD_PID=$!
-
/system/bin/setprop "net.gprs.ppp-exit" "$PPPD_EXIT"
call-pppd脚本需要我们传进来6个参数,比如:
-
asprintf(&cmd, "/etc/ppp/call-pppd "
-
"\"%s 115200\" " // $1
-
"\"novj novjccomp noccp ipcp-accept-local ipcp-accept-remote\" " // $2
-
"\"%s\" \"%s\" " // $3 $4
-
"\"%s\" \"%s\" &", // $5 $6
-
s_pppChannel, user, password, conn_script, disconn_script);
-
ret = system(cmd);
system(const char *command)函数用来执行call-pppd脚本,log:
至此,数据业务建立完成,通过ifconfig命令查看,生成由ppp设备节点。