編輯:關於Android編程
本章簡單講述下android實現自動撥號的功能,該功能利用了系統啟動的rild的服務來實現,因為rild的服務是殺不死的,所以利用這一點,可以使撥號失敗或網絡斷掉後自動重撥,來增強上網的可靠性。這裡只實現撥號功能,把ril庫實現的一些功能都去掉了。
一、修改rild程序源碼
把 .../hardware/ril裡面的文件全部刪掉,創建rild文件夾,把以下面代碼放到新建的文件夾下。
1、rild.c
#define LOG_TAG "RILD" #include#include #include #include #include #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#include #include #include #include #include #include #include #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, "");//獲取IP if (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#include //ALOG*() #include //property_set() #define PPPD_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.c LOCAL_SHARED_LIBRARIES := \ libcutils \ libdl LOCAL_LDLIBS += -lpthread LOCAL_MODULE:= rild LOCAL_MODULE_TAGS := optional include $(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 retrieved PPPD_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 defaultroute usepeerdns crtscts user card password card noipdefault ipcp-accept-local \ ipcp-accept-remote PPPD_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 "" at OK atd*99***1# CONNECT
三、修改ini.rc腳本
再修改init.rc前一定要先編譯好源碼,因為修改的是編譯後生成的文件,因為改源文件有點麻煩。
打開 .../ out/target/product/sabresd_6dq/root/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之後看看是不是該進程又運行了。
雖然視覺上的反饋通常是給用戶提供信息最快的方式,但這要求用戶把注意力設備上。當用戶不能查看設備時,則需要一些其他通信的方法。Android提供了強大的文字轉語音Text-
Android 目前支持下面幾個版本的OpenGL ES API : OpenGL ES 1.0 和 1.1 :Android 1.0和更高的版本支持這個API規范。 O
在實際的項目開發過程中(應用的APP),我們用網絡存儲的地方比較多。今天我們一起來談談網絡存儲的功能。什麼是網絡存儲?就是我們的數據存儲在一個服務器上,app客戶端類
為要獲取網絡上的Json所以需要服務器端提供的支持。一、創建服務器端:服務器端項目結構:服務器端運行效果圖:第一步:創建業務所需的JavaBean復制代碼 代碼如下:&n