本章简单讲述下android实现自动拨号的功能,该功能利用了系统启动的rild的服务来实现,因为rild的服务是杀不死的,所以利用这一点,可以使拨号失败或网络断掉后自动重拨,来增强上网的可靠性。这里只实现拨号功能,把ril库实现的一些功能都去掉了。

一、修改rild程序源码

把 .../hardware/ril里面的文件全部删掉,创建rild文件夹,把以下面代码放到新建的文件夹下。

1、rild.c

#define LOG_TAG "RILD"#include <unistd.h>#include <pthread.h>#include <utils/Log.h>#include <sys/types.h>#include <sys/stat.h>#include "ril_fun.h"int main(int argc, char *argv[]){int opt;int err;pthread_t tid;char buf[PROPERTY_VALUE_MAX];static int device_fd;static char * device_path = NULL;umask(S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH);    while ( -1 != (opt = getopt(argc, argv, "d:"))) {//用来分析main函数传递的命令行参数switch (opt) {            case 'd':                device_path = optarg;                ALOGD("Opening tty device %s\n", device_path);            break;            default:                ALOGD("Not tty device");                goto done;        }    }device_fd = device_open(device_path);//打开设备节点device_init(device_fd);//初始化设备节点property_set("ctl.stop", PPPD_SERVICE_NAME);//设置pppd_gprs属性为停止request_setup_datacall(device_fd);//继续执行拨号pthread_create(&tid,NULL,ip_detection,(void *)device_fd);//创建查询IP线程,使断网后重新拨号done:while(1){sleep(0x00ffffff);}return 0;}

2、ril_fun.c

#define LOG_TAG "RIL"#include <stdio.h>#include <string.h>#include <stdlib.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <termios.h>#include <sys/select.h>#include "ril_fun.h"#define PPPD_EXIT_CODE      "net.gprs.ppp-exit"#define PPP_NET_LOCAL_IP    "net.ppp0.local-ip"#define PPP_SYSFS_RETRY    5#define PPP_OPERSTATE_PATH  "/sys/class/net/ppp0/operstate"static int pppd_started = 0;int device_open(char *device_path){int device_fd = -1;while (device_fd < 0) {         if (device_path != NULL) {            device_fd = open (device_path, O_RDWR);//打开串口AT模块的设备         }        if (device_fd < 0) {ALOGD ("opening AT interface. retrying...");sleep(3);}    }return device_fd;}void device_init(int device_fd){struct termios options;tcgetattr(device_fd, &options);//获取串口属性cfsetispeed(&options, B115200);//设置接收波特率cfsetospeed(&options, B115200);//设置发送波特率options.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|IGNCR|ICRNL|IXON);options.c_cflag &= ~PARENB; //无奇偶校验位options.c_cflag &= ~CSTOPB;//停止位为1位options.c_cflag &= ~CSIZE;options.c_cflag |= CS8;//数据位为8位options.c_lflag   &=   ~(ICANON   |   ECHO   |   ECHOE   |   ISIG);tcsetattr(device_fd,TCSANOW,&options);} int at_send_command(int device_fd, char *cmd){int ret;ret = write(device_fd, cmd, strlen(cmd));return ret;}void request_setup_datacall(int device_fd) {const char *apn = "cmnet";    char *cmd = NULL;    int err;    ALOGD("requesting data connection to APN '%s'", apn);    if(pppd_started) {ALOGD("Stop existing PPPd before activating PDP");property_set("ctl.stop", PPPD_SERVICE_NAME);//设置pppd_gprs属性为停止pppd_started = 0;    }    err = at_send_command(device_fd, "at$qcpdplt=0");    asprintf(&cmd, "AT+CGDCONT=1,\"IP\",\"%s\",,0,0", apn);//设置PDP上下文    err = at_send_command(device_fd, cmd);    free(cmd);    if (err < 0 ) {        ALOGD("AT Send Command error!");    }    err = property_set(PPPD_EXIT_CODE, "");//设置net.gprs.ppp-exit为空    if (err < 0) {ALOGW("Set PPPD_EXIT_CODE failed!");goto ppp_error;}    err = property_set(PPP_NET_LOCAL_IP, "");//设置net.ppp0.local-ip为空    if (err < 0) {ALOGW("Set PPPD_NET_LOCAL_IP failed!");goto ppp_error;}    err = property_set("ctl.start", PPPD_SERVICE_NAME);//设置pppd_gprs属性为启动    pppd_started = 1;    if (err < 0) {ALOGW("Can not start PPPd");goto ppp_error;    }    ALOGD("PPPd started");    return;ppp_error:    at_send_command(device_fd, "AT+CGACT=0,1");//PDP上下文去激活    if(pppd_started) {property_set("ctl.stop", PPPD_SERVICE_NAME);pppd_started = 0;    }}void *ip_detection(void *arg) {int fd;int err;int device_fd = (int)arg;    char buffer[20];    char exit_code[PROPERTY_VALUE_MAX];    static char local_ip[PROPERTY_VALUE_MAX];static int pppd_started = 0;    sleep(2);    while(1){property_get(PPPD_EXIT_CODE, exit_code, "");//获取pppd的退出状态if(strcmp(exit_code, "") != 0) {//检测pppd是否异常退出ALOGW("PPPd exit with code %s", exit_code);request_setup_datacall(device_fd);//继续执行拨号goto done;}        fd  = open(PPP_OPERSTATE_PATH, O_RDONLY);//读取/sys/class/net/ppp0/operstate来监控数据网络数据的状态        if (fd >= 0)  {buffer[0] = 0;            read(fd, buffer, sizeof(buffer));close(fd);ALOGW("buffer = %s", buffer);if(!strncmp(buffer, "up", strlen("up")) || !strncmp(buffer, "unknown", strlen("unknown"))) {memset(local_ip,'\0',sizeof(local_ip));err = property_get(PPP_NET_LOCAL_IP, local_ip, "");//获取IPif (err < 0) {ALOGW("Get PPPD_NET_LOCAL_IP failed!");}if(!strcmp(local_ip, "")) {ALOGW("PPP link is up but no local IP is assigned. Will retry times after %d seconds",PPP_SYSFS_RETRY);property_set("ctl.stop", PPPD_SERVICE_NAME);//如果没有IP停止pppd} else {ALOGD("PPP link is up with local IP address %s", local_ip);}} else {ALOGW("PPP link status in %s is %s. Will retry times after %d seconds", \PPP_OPERSTATE_PATH, buffer, PPP_SYSFS_RETRY);property_set("ctl.stop", PPPD_SERVICE_NAME);//如果数据网络数据的状态不对停止pppd}} else {        ALOGW("Can not detect PPP state in %s. Will retry  times after %d seconds", \    PPP_OPERSTATE_PATH ,PPP_SYSFS_RETRY);request_setup_datacall(device_fd);//继续执行拨号}done:        sleep(PPP_SYSFS_RETRY);    }    return NULL;}

3、ril_fun.h

#ifndef _RIL_FUN_H_#define _RIL_FUN_H_#include <unistd.h>#include <utils/Log.h> //ALOG*()#include <cutils/properties.h> //property_set()#definePPPD_SERVICE_NAME "pppd_gprs"/************************************************************** 功能:打开串口设备文件* 参数:device_path: 串口设备文件名* 返回值:串口设备文件描述符**************************************************************/int device_open(char *device_path);/************************************************************** 功能:初始化设备节点* 参数:device_fd: 串口设备文件描述符          * 返回值:无**************************************************************/void device_init(int device_fd);/************************************************************** 功能:发送AT指令函数* 参数:device_fd: 串口设备文件描述符*           cmd:AT命令          * 返回值:ret:状态**************************************************************/int at_send_command(int device_fd, char *cmd);/************************************************************** 功能:建立拨号函数* 参数:device_fd: 串口设备文件描述符          * 返回值:无**************************************************************/void request_setup_datacall(int device_fd);/************************************************************** 功能:创建查询IP线程* 参数:arg: void类型指针         * 返回值:NULL**************************************************************/void *ip_detection(void *arg);#endif

4、Android.mk

LOCAL_PATH:= $(call my-dir)include $(CLEAR_VARS)LOCAL_SRC_FILES:= \rild.c \ril_fun.cLOCAL_SHARED_LIBRARIES := \libcutils \libdlLOCAL_LDLIBS += -lpthreadLOCAL_MODULE:= rildLOCAL_MODULE_TAGS := optionalinclude $(BUILD_EXECUTABLE)

上述文件添加好后,进行编译,在编译前如果之前编译过要进行清理,执行make clean

二、把下面的脚本放到板子的/etc/ppp下

1、init.gprs-pppd

#!/system/bin/sh# An unforunate wrapper script # so that the exit code of pppd may be retrievedPPPD_PID=/system/bin/setprop "net.gprs.ppp-exit" "" #设置net.gprs.ppp-exit为空/system/bin/log -t pppd "Starting pppd"/system/bin/pppd connect 'chat -v -s -r "/var/log/chat.log" -f "/etc/ppp/3gdata_call.conf"' disconnect \'chat -r "/var/log/chat.log" -t 30 -e -v "" +++ATH "NO CARRIER"' /dev/ttyUSB3 115200 mru 1280 mtu 1280 \nodetach debug dump defaultroute usepeerdns novj novjccomp crtscts user card password card noipdefault ipcp-accept-local  \ipcp-accept-remote linkname ppp0PPPD_EXIT=$? #获得执行命令后的返回值PPPD_PID=$!  #最后运行的后台进程的PID/system/bin/log -t pppd "pppd exited with $PPPD_EXIT" /system/bin/setprop "net.gprs.ppp-exit" "$PPPD_EXIT" #把返回值设置给net.gprs.ppp-exit

注:脚本中的/dev/ttyUSB3为模块USB串口的Modem口。

2、3gdata_call.conf

ABORT "NO CARRIER"ABORT "NO DIALTONE"ABORT "ERROR"ABORT "NO ANSWER"ABORT "BUSY"TIMEOUT 120"" atOK atd*99***1#CONNECT

三、修改ini.rc脚本

打开 .../device/fsl/imx6/etc/init.rc按照如下红色框进行修改

添加修改新加入文件权限的语句。

注:/dev/ttyUSB2是模块USB串口的AT口。

到此,就可以进行打包 make snod ,烧写镜像进行测试了。

可以用命令:logcat -b radio 查看rild 输出的信息进行调试。如果一切正常会打印出IP(或用命令 necfg 查看IP),有IP后用命令 ping 202.108.22.5 (百度IP)看下网络是否能ping通。如果能ping通证明自动拨号已经成功。此时用命令 ps查看rild和pppd进程号,用命令kill -9 <进程号> 杀死随便一个进程,在5s之后看看是不是该进程又运行了。

更多相关文章

  1. Android透明状态栏与沉浸模式全解
  2. Android(安卓)Studio 设置代码提示和代码自动补全快捷键--Eclips
  3. Android(安卓)6.0 sensor 框架详解 (application层)
  4. 如题,打算自己编个小游戏发在Android(安卓)Market上,但是不知道怎
  5. android中定时-开“关机”的实现
  6. 第2章 初识Android(安卓)App(第2讲)
  7. android:windowIsTranslucent 的好处 与 引发的部分问题
  8. Android(安卓)Wear 之 为通知添加动作
  9. 利用adb无线连接android手机进行调式 无需获得root权限

随机推荐

  1. 数十亿用户的Facebook如何进行贝叶斯系统
  2. 开源数据搜索软件公司Elasticsearch上市,
  3. Uber开源Marmaray:基于Hadoop的通用数据摄
  4. 贝叶斯之父Judea Pearl推荐:机器学习因果
  5. 日均万亿事件:Netflix怎么做实时流处理?
  6. 最有趣的机器学习可视化图集
  7. 暴力堆数据没用!NLP和语音技术突破难在哪?
  8. DeepMind PotArt多任务深度强化学习获突
  9. 大数据凉了?No,流式计算浪潮才刚刚开始!
  10. 作为普通Ruby开发,我如何从零转型机器学习