您的位置:首页 > 移动开发 > Android开发

android通过jni控制wifi service服务的流程分析

2012-11-11 12:18 681 查看
android_net_wifi_startSupplicant这个就是jni函数

=>wifi_start_supplicant

static const
char SUPP_CONFIG_TEMPLATE[]=
"/system/etc/wifi/wpa_supplicant.conf";

static const
char SUPP_CONFIG_FILE[]
= "/data/misc/wifi/wpa_supplicant.conf";

=>ensure_config_file_exists该函数将SUPP_CONFIG_TEMPLATE文件拷贝到SUPP_CONFIG_FILE目录下,然后chown改变SUPP_CONFIG_FILE属组

=>control_supplicant(1),开启wpa_supplicant.

首先会检测当前property_get(SUPP_PROP_NAME, supp_status,
NULL)是否已经开启,如果没有,那么调用

property_set(ctrl_prop, SUPPLICANT_NAME);设置prop来开启,然后最长等待20s,直到期望的控制状态正确.

也就是等待system/rootdir/init.rc脚本中名为wpa_supplicant的服务进程运行.

system/rootdir/init.rc脚本中的service后台服务进程定义如下:

...

service wpa_supplicant /system/bin/wpa_supplicant
-Dwext -ieth0
-c/data/misc/wifi/wpa_supplicant.conf

disabled

...

static const
char SUPPLICANT_NAME[]
= "wpa_supplicant";

"wpa_supplicant"为prop字符串,上面property_set(ctrl_prop, SUPPLICANT_NAME);

=>handle_property_set_fd 如果为"ctl."字符串,那么将调用service服务进程控制函数

if(memcmp(msg.name,"ctl.",4)
== 0)
{

handle_control_message((char*) msg.name
+ 4,
(char*) msg.value);

}

=>handle_control_message

=>msg_start

=>service_start

execve(svc->args[0],
(char**) svc->args,
(char**) ENV);

//执行/system/bin/wpa_supplicant程序,为什么是这个,如下:[luther.gliethttp]

/init/init.c进程是这样对service后台服务进程解析的

1.parse_config_file("/init.rc");

2.printf(tmp,
"/init.%s.rc", hardware);

parse_config_file(tmp);

3.sprintf(tmp,
"/system/etc/init.%s.rc", hardware);

parse_config_file(tmp);

parse_config_file

=>parse_config

=>state->context
= parse_service(state, nargs, args)

=>

nargs -= 2;

svc->name
= args[1];

svc->classname
= "default";

memcpy(svc->args, args
+ 2,
sizeof(char*)
* nargs);

//这样svc->args[0]..[3]为"/system/bin/wpa_supplicant -Dwext -ieth0 -c/data/misc/wifi/wpa_supplicant.conf"了[luther.glithttp]

svc->args[nargs]
= 0;//参数结尾添0

svc->nargs
= nargs;

list_add_tail(&service_list,
&svc->slist);

=>state->parse_line
= parse_line_service;

=>parse_line_service

那么handle_property_set_fd又是怎么来的呢,那么我们继续看,

init/init.c第一个kernel启动的用户空间引用程序:

int main(int argc,
char **argv)

{

...

property_set_fd = start_property_service();

...

ufds[1].fd
= property_set_fd;

ufds[1].events
= POLLIN;

...

for(;;)
{

...

nr = poll(ufds, 3, timeout);
//做poll等待[luther.gliethttp].

...

if
(ufds[1].revents
== POLLIN)

handle_property_set_fd(property_set_fd);//从java层通过unix管道传来了控制数据,java层执行的reboot和powerdown操作也由该函数处理.

..

}

...

return 0;

}

#define PROP_SERVICE_NAME
"property_service"

int start_property_service(void)

{

...

fd = create_socket(PROP_SERVICE_NAME,
SOCK_STREAM, 0666, 0, 0);

...

listen(fd, 8);

return fd;

}

#define ANDROID_SOCKET_DIR        "/dev/socket"

int create_socket(const
char *name,
int type, mode_t perm, uid_t uid, gid_t gid)

{

...

snprintf(addr.sun_path,
sizeof(addr.sun_path), ANDROID_SOCKET_DIR"/%s",

name);

...

}

所以这个property_set的unix通信文件位于:"/dev/socket/property_service"下.

当然java的jni应用程序链接调用的是system/lib/libandroid_runtime.so这个so库中的服务,不过和init中的没有区别[luther.gliethttp].
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: