=============================================================================================================
libs/android_runtime/android_net_wifi_Wifi.cpp
部分jni接口
staticJNINativeMethod gWifiMethods[]={
{"loadDriver","()Z",(void*)android_net_wifi_loadDriver},
{"setPowerModeCommand","(I)Z",(void*)android_net_wifi_setPowerModeCommand},//电源管理
{"connectToSupplicant","()Z",(void*)android_net_wifi_connectToSupplicant},
{"waitForEvent","()Ljava/lang/String;",(void*)android_net_wifi_waitForEvent},
{"disconnectCommand","()Z",(void*)android_net_wifi_disconnectCommand},
...
};
intregister_android_net_wifi_WifiManager(JNIEnv*env)
{
...
returnAndroidRuntime::registerNativeMethods(env,
WIFI_PKG_NAME,gWifiMethods,NELEM(gWifiMethods));//登记jni
}
libs/android_runtime/AndroidRuntime.cpp
staticconstRegJNIRec gRegJNI[]={
...
REG_JNI(register_android_net_wifi_WifiManager),
...
};
intAndroidRuntime::startReg(JNIEnv*env)
{
...
register_jni_procs(gRegJNI,NELEM(gRegJNI),env);
...
}
AndroidRuntime::start
=>startReg(env)即调用方法int AndroidRuntime::startReg(JNIEnv*env)
=============================================================================================================
wifi_load_driver
wifi_start_supplicant
=>ensure_config_file_exists
//检查/data/misc/wifi/wpa_supplicant.conf文件是否存在,如果不存在,那么从/system/etc/wifi/wpa_supplicant.conf动态拷贝一份
android_net_wifi_connectToSupplicant
=>wifi_connect_to_supplicant
=>
ctrl_conn=wpa_ctrl_open(ifname);
monitor_conn=wpa_ctrl_open(ifname);
wpa_ctrl_attach(monitor_conn);
android_net_wifi_waitForEvent
=>wifi_wait_for_event
=>wpa_ctrl_recv(monitor_conn,buf,&nread);
=>recv(ctrl->s,reply,*reply_len,0);//阻塞等待wpa_supplicant的netlink数据过来
=>如果接收的buf数据区,buf[0]为'<',那么说明有level级别信息,所以将'<'...'>'数据剔除,然后wifi_wait_for_event函数返回[luther.gliethttp].
java/android/android/net/wifi/WifiMonitor.java
publicclassWifiMonitor{
...
publicvoidstartMonitoring(){
newMonitorThread().start();//启动java线程
}
classMonitorThreadextendsThread{
publicMonitorThread(){
super("WifiMonitor");
}
publicvoidrun(){
for(;;){
ensureSupplicantConnection();//=>WifiNative.connectToSupplicant调用jni函数android_net_wifi_connectToSupplicant
StringeventStr=WifiNative.waitForEvent();//=>调用jni函数android_net_wifi_waitForEvent
//private static final int CONNECTED = 1;
//private static final int DISCONNECTED = 2;
//private static final String eventPrefix = "CTRL-EVENT-";
//private static final int eventPrefixLen = eventPrefix.length();
//private static final String connectedEvent = "CONNECTED";
//private static final String disconnectedEvent = "DISCONNECTED";
StringeventName=eventStr.substring(eventPrefixLen);//去掉"CTRL-EVENT-"字符串
intnameEnd=eventName.indexOf(' ');//找到随后的空格位置,这在wpa_supplicant发送时
//#define WPA_EVENT_CONNECTED "CTRL-EVENT-CONNECTED "中,已经内置空格了.
if(nameEnd!=-1)
eventName=eventName.substring(0,nameEnd);
intevent;
if(eventName.equals(connectedEvent))//检测netlink过来的字符串action类型
event=CONNECTED;
elseif(eventName.equals(disconnectedEvent))
event=DISCONNECTED;
...
intind=eventStr.indexOf(" - ");//CTRL-EVENT-CONNECTED - Connection to ...
if(ind!=-1)
eventData=eventStr.substring(ind+3);
//剔除前导控制字符,将" - "后面的描述字符串作为真实数据,继续处理
...
if(event==STATE_CHANGE){
handleSupplicantStateChange(eventData);
}elseif(event==DRIVER_STATE){
handleDriverEvent(eventData);
}else{
handleEvent(event,eventData);//对于CONNECTED和DISCONNECTED等netlink事件将执行此操作来处理[luther.gliethttp]
// If supplicant is gone, exit the thread
if(event==TERMINATING){
break;
}
}
...
voidhandleEvent(intevent,Stringremainder){
switch(event){
caseDISCONNECTED:
handleNetworkStateChange(NetworkInfo.DetailedState.DISCONNECTED,remainder);
break;
caseCONNECTED:
handleNetworkStateChange(NetworkInfo.DetailedState.CONNECTED,remainder);//控制界面显示
break;
...
}
publicclassWifiStateTrackerextendsNetworkStateTracker{
...
publicvoidstartEventLoop(){
mWifiMonitor.startMonitoring();//启动上面的MonitorThread线程
}
...
}
java/services/com/android/server/WifiService.java
publicclassWifiServiceextendsIWifiManager.Stub{
...
privatebooleansetWifiEnabledBlocking(booleanenable){
finalinteventualWifiState=enable?WIFI_STATE_ENABLED:WIFI_STATE_DISABLED;
...
if(enable){
if(WifiNative.loadDriver()){
Log.e(TAG,"Failed to load Wi-Fi driver.");
updateWifiState(WIFI_STATE_UNKNOWN);
returnfalse;
}
if(WifiNative.startSupplicant()){
WifiNative.unloadDriver();
Log.e(TAG,"Failed to start supplicant daemon.");
updateWifiState(WIFI_STATE_UNKNOWN);
returnfalse;
}
mWifiStateTracker.startEventLoop();
//启动MonitorThread线程,等待wpa_supplicant将netlink数据转发过来,然后根据netlink动作类型,进一步影响界面显示[luther.gliethttp].
}
...
}
java/android/android/net/wifi/WifiStateTracker.java
电源管理
privatevoidhandleConnectedState(){
...
mDhcpTarget.obtainMessage(EVENT_DHCP_START).sendToTarget();//传递到下面的handleMessage方法
...
}
publicvoidonChange(booleanselfChange){
...
handleConnectedState();
...
}
publicclassWifiStateTrackerextendsNetworkStateTracker{
...
publicvoidhandleMessage(Message msg){
switch(msg.what){
caseEVENT_SUPPLICANT_CONNECTION:
caseEVENT_NETWORK_STATE_CHANGED:
handleConnectedState();//调用
...
privateclassDhcpHandlerextendsHandler{
privateHandlermTarget;
publicDhcpHandler(Looper looper,Handlertarget){
super(looper);
mTarget=target;
}
publicvoidhandleMessage(Message msg){
intevent;
//private static final int DRIVER_POWER_MODE_AUTO = 0;
//private static final int DRIVER_POWER_MODE_ACTIVE = 1;
switch(msg.what){
caseEVENT_DHCP_START:
synchronized(this){
WifiNative.setPowerModeCommand(DRIVER_POWER_MODE_ACTIVE);//设置电源模式,调用android_net_wifi_setPowerModeCommand
}
Log.d(TAG,"DhcpHandler: DHCP request started");
//libs/android_runtime/android_net_NetUtils.cpp
//static JNINativeMethod gNetworkUtilMethods[] = {
//{ "runDhcp", "(Ljava/lang/String;Landroid/net/DhcpInfo;)Z", (void *)android_net_utils_runDhcp },
// ...
//};
if(NetworkUtils.runDhcp(mInterfaceName,mDhcpInfo)){//执行dhcp申请ip地址操作
event=EVENT_INTERFACE_CONFIGURATION_SUCCEEDED;
if(LOCAL_LOGD)Log.v(TAG,"DhcpHandler: DHCP request succeeded");
}else{
event=EVENT_INTERFACE_CONFIGURATION_FAILED;
Log.i(TAG,"DhcpHandler: DHCP request failed: "+
NetworkUtils.getDhcpError());
//如果dhcpcd分配ip失败,那么Message.obtain(mTarget, event).sendToTarget();将执行
//WifiNative.disconnectCommand();即:static JNINativeMethod gWifiMethods[] = {
//android_net_wifi_disconnectCommand发送"DISCONNECT"字符串[luther.gliethttp]
//然后在wpa_supplicant服务端执行wpa_supplicant_ctrl_iface_process
//wpa_supplicant_disassociate
}
synchronized(this){
WifiNative.setPowerModeCommand(DRIVER_POWER_MODE_AUTO);
}
Message.obtain(mTarget,event).sendToTarget();
break;
}
}
}
...
/**
* Send the tracker a notification that a connection to the supplicant
* daemon has been established.
*/
//在上面的public class WifiMonitor=>ensureSupplicantConnection
//=>
//while (!supplicantConnected) {
// boolean connected;
//synchronized (mWifiStateTracker) {
//connected = WifiNative.connectToSupplicant();//如果没有连接成功,那么while循环尝试,直到尝试成功,或者定义了oneShot,仅一次尝试
//=>mWifiStateTracker.notifySupplicantConnection();//如果WifiNative.connectToSupplicant()成功,那么将执行
//mWifiStateTracker.notifySupplicantConnection();的调用.
voidnotifySupplicantConnection(){//向对象发送message
Message.obtain(this,EVENT_SUPPLICANT_CONNECTION).sendToTarget();
}
voidnotifyStateChange(SupplicantState newState){
Message.obtain(this,EVENT_SUPPLICANT_STATE_CHANGED,newState).sendToTarget();
}
...
}
staticjboolean android_net_wifi_setPowerModeCommand(JNIEnv*env,jobject clazz,jint mode)
{
charcmdstr[256];
sprintf(cmdstr,"DRIVER POWERMODE %d",mode);
returndoBooleanCommand(cmdstr,"OK");
}
android_net_wifi_setPowerModeCommand
=>doBooleanCommand
=>doCommand
=>wifi_command
=>wifi_send_command
=>wpa_ctrl_request
=>send给wpa_supplicant
然后wpa_supplicant将做如下接收操作:
system/extra/wpa_supplicant/main.c
=>wpa_supplicant_add_iface
=>wpa_supplicant_init_iface2
=>wpa_supplicant_ctrl_iface_init
=>注册ctrl_conn控制端口和monitor_conn监听端口的处理函数
eloop_register_read_sock(priv->sock,wpa_supplicant_ctrl_iface_receive,wpa_s,priv);//ctrl_conn端口的handler处理函数
wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);//monitor_conn端口的回调处理函数,处理netlink数据到所有monitor_conn监听端口
=>wpa_supplicant_ctrl_iface_receive//对于unix通信方式
=>wpa_supplicant_ctrl_iface_process
=>如果wpa_cli发送的是wpa_clidriverxxx形式的命令,那么调用这个函数
if(os_strncmp(buf,"DRIVER ",7)==0){//掠过前7个,直接将命令传过去
reply_len=wpa_supplicant_driver_cmd(wpa_s,buf+7,reply,reply_size);
=>wpa_supplicant_driver_cmd
=>wpa_drv_driver_cmd
=>自定义DRIVER扩展处理函数,所以对于java传递过来的power电源管理命令,wpa_drv_driver_cmd将收到"POWERMODE 0"或者"POWERMODE 1"字符串[luther.gliethttp]
=============================================================================================================
jni
=>runDhcp
=>android_net_utils_runDhcp
libs/netutils/dhcp_utils.c
=>dhcp_do_request
=>
staticconstcharDAEMON_NAME[]="dhcpcd";
staticconstcharDAEMON_PROP_NAME[]="init.svc.dhcpcd";
staticconstcharDHCP_PROP_NAME_PREFIX[]="dhcp";
constchar*ctrl_prop="ctl.start";
constchar*desired_status="running";
snprintf(result_prop_name,sizeof(result_prop_name),"%s.%s.result",
DHCP_PROP_NAME_PREFIX,
interface);
property_set(result_prop_name,"");//设置dhcp.eth0.result="";等到成功完成dhcp之后,
property_set(ctrl_prop,DAEMON_NAME);//向名字为dhcpcd的service,发送"ctrl.start"启动命令字,该service在init.rc中
//init.rc中dhcpcd服务进程命令字
//service dhcpcd /system/bin/dhcpcd eth0
// disabled
// oneshot
wait_for_property(DAEMON_PROP_NAME,desired_status,10);
//init.c=>init进程
//=>handle_property_set_fd因为是"ctrl.start"命令字,所以调用handle_control_message处理控制信息
//=>handle_control_message
//=>msg_start
//=>
// struct service *svc = service_find_by_name(name);
// service_start(svc);//启动svc,即执行:/system/bin/dhcpcd eth0
//=>service_start
//=>pid = fork();
// if(pid == 0)execve(svc->args[0], (char**) svc->args, (char**) ENV);子进程执行execve运行/system/bin/dhcpcd,参数为eth0
//=>否则父进程,即init进程将
//=>notify_service_state(svc->name, "running");设置该svc的状态prop
// snprintf(pname, sizeof(pname), "init.svc.%s", name);
// property_set(pname, state);//所以这样上面wait_for_property(DAEMON_PROP_NAME, desired_status, 10);也才能够正常pass[luther.gliethttp].
wait_for_property(result_prop_name,NULL,15);//等待dhcp.eth0.result=非空
=============================================================================================================
system/extra/dhcpcd-4.0.0-beta9/dhcpcd.c
dhcpcd
=>main
# define SYSCONFDIR"/system/etc/dhcpcd"
#definePACKAGE"dhcpcd"
# defineCONFIGSYSCONFDIR"/"PACKAGE".conf"
# define LIBEXECDIR"/system/etc/dhcpcd"
# define SCRIPTLIBEXECDIR"/"PACKAGE"-run-hooks"
=>strlcpy(options->script,SCRIPT,sizeof(options->script));//默认的options->script="/system/etc/dhcpcd/dhcpcd-run-hooks"
=>f=fopen(cf?cf:CONFIG,"r");//如果没有指定.conf文件,那么使用默认.conf文件
=>parse_config_line//解析"/system/etc/dhcpcd/dhcpcd.conf"默认配置文件
=>parse_option
=>如果在"/system/etc/dhcpcd/dhcpcd.conf"有"script"这个节
=>那么执行strlcpy(options->script,oarg,sizeof(options->script));直接拷贝
/*
{"script", required_argument, NULL, 'c'},
{"option", required_argument, NULL, 'o'},
"/system/etc/dhcpcd/dhcpcd.conf"中的部分内容如下:
...
option domain_name_servers, domain_name, domain_search, host_name
...
*/
=>dhcp_run
=>handle_dhcp_packet
=>handle_dhcp
=>bind_dhcp
reason="TIMEOUT";reason="BOUND";reason="REBIND";reason="RENEW";
system/extra/dhcpcd-4.0.0-beta9/configure.c
=>configure(iface,reason,state->new,state->old,&state->lease,options,1);
//如果dhcp超时或者dhcp成功,都会调用exec_script来执行脚本,
//执行setprop dhcp.${interface}.result "failed"或者
//执行setprop dhcp.${interface}.result "ok"
=>exec_script(options,iface->name,reason,NULL,old);
=>然后configure_env通过环境变量将reason传递到脚本中
intexec_script(conststructoptions*options,constchar*iface,constchar*reason,
conststructdhcp_message*dhcpn,conststructdhcp_message*dhcpo)
=>pid=fork();
=>if(pid==0)execve(options->script,argv,env);//子进程执行脚本,默认"/system/etc/dhcpcd/dhcpcd-run-hooks"
//dhcpcd-run-hooks脚本会根据level值,决定是否执行system/etc/dhcpcd/dhcpcd-hook/*目录下的相应文件
//我们的系统在该system/etc/dhcpcd/dhcpcd-hook/*目录下有如下3个文件
//95-configured
//20-dns.conf
//01-test
=>父进程返回while(waitpid(pid,&status,0)==-1)等待子进程脚本执行完成
system/extra/dhcpcd-4.0.0-beta9/dhcpcd-hooks/20-dns.conf
system/extra/dhcpcd-4.0.0-beta9/dhcpcd-hooks/95-configured
...
setprop dhcp.${interface}.ipaddress"${new_ip_address}"
setprop dhcp.${interface}.result"ok"//设置属性为ok
setprop dhcp.${interface}.result"failed"
...
=============================================================================================================
inet_init、tcp_prot
sock->ops->sendmsg(iocb,sock,msg,size);
=>inetsw_array[]
=>inet_stream_ops
=>tcp_sendmsg
=============================================================================================================
wpa_cli.c
=>main
=>wpa_cli_interactive
=>wpa_cli_recv_pending(monitor_conn,0,0);//阻塞等待wpa_supplicant发送数据过来
=>如果action_monitor为true,那么将执行一些简单加工操作,否则将直接将wpa_supplicant发过来的数据打印到console上[luther.gliethttp].
libs/android_runtime/android_net_wifi_Wifi.cpp
部分jni接口
staticJNINativeMethod gWifiMethods[]={
{"loadDriver","()Z",(void*)android_net_wifi_loadDriver},
{"setPowerModeCommand","(I)Z",(void*)android_net_wifi_setPowerModeCommand},//电源管理
{"connectToSupplicant","()Z",(void*)android_net_wifi_connectToSupplicant},
{"waitForEvent","()Ljava/lang/String;",(void*)android_net_wifi_waitForEvent},
{"disconnectCommand","()Z",(void*)android_net_wifi_disconnectCommand},
...
};
intregister_android_net_wifi_WifiManager(JNIEnv*env)
{
...
returnAndroidRuntime::registerNativeMethods(env,
WIFI_PKG_NAME,gWifiMethods,NELEM(gWifiMethods));//登记jni
}
libs/android_runtime/AndroidRuntime.cpp
staticconstRegJNIRec gRegJNI[]={
...
REG_JNI(register_android_net_wifi_WifiManager),
...
};
intAndroidRuntime::startReg(JNIEnv*env)
{
...
register_jni_procs(gRegJNI,NELEM(gRegJNI),env);
...
}
AndroidRuntime::start
=>startReg(env)即调用方法int AndroidRuntime::startReg(JNIEnv*env)
=============================================================================================================
wifi_load_driver
wifi_start_supplicant
=>ensure_config_file_exists
//检查/data/misc/wifi/wpa_supplicant.conf文件是否存在,如果不存在,那么从/system/etc/wifi/wpa_supplicant.conf动态拷贝一份
android_net_wifi_connectToSupplicant
=>wifi_connect_to_supplicant
=>
ctrl_conn=wpa_ctrl_open(ifname);
monitor_conn=wpa_ctrl_open(ifname);
wpa_ctrl_attach(monitor_conn);
android_net_wifi_waitForEvent
=>wifi_wait_for_event
=>wpa_ctrl_recv(monitor_conn,buf,&nread);
=>recv(ctrl->s,reply,*reply_len,0);//阻塞等待wpa_supplicant的netlink数据过来
=>如果接收的buf数据区,buf[0]为'<',那么说明有level级别信息,所以将'<'...'>'数据剔除,然后wifi_wait_for_event函数返回[luther.gliethttp].
java/android/android/net/wifi/WifiMonitor.java
publicclassWifiMonitor{
...
publicvoidstartMonitoring(){
newMonitorThread().start();//启动java线程
}
classMonitorThreadextendsThread{
publicMonitorThread(){
super("WifiMonitor");
}
publicvoidrun(){
for(;;){
ensureSupplicantConnection();//=>WifiNative.connectToSupplicant调用jni函数android_net_wifi_connectToSupplicant
StringeventStr=WifiNative.waitForEvent();//=>调用jni函数android_net_wifi_waitForEvent
//private static final int CONNECTED = 1;
//private static final int DISCONNECTED = 2;
//private static final String eventPrefix = "CTRL-EVENT-";
//private static final int eventPrefixLen = eventPrefix.length();
//private static final String connectedEvent = "CONNECTED";
//private static final String disconnectedEvent = "DISCONNECTED";
StringeventName=eventStr.substring(eventPrefixLen);//去掉"CTRL-EVENT-"字符串
intnameEnd=eventName.indexOf(' ');//找到随后的空格位置,这在wpa_supplicant发送时
//#define WPA_EVENT_CONNECTED "CTRL-EVENT-CONNECTED "中,已经内置空格了.
if(nameEnd!=-1)
eventName=eventName.substring(0,nameEnd);
intevent;
if(eventName.equals(connectedEvent))//检测netlink过来的字符串action类型
event=CONNECTED;
elseif(eventName.equals(disconnectedEvent))
event=DISCONNECTED;
...
intind=eventStr.indexOf(" - ");//CTRL-EVENT-CONNECTED - Connection to ...
if(ind!=-1)
eventData=eventStr.substring(ind+3);
//剔除前导控制字符,将" - "后面的描述字符串作为真实数据,继续处理
...
if(event==STATE_CHANGE){
handleSupplicantStateChange(eventData);
}elseif(event==DRIVER_STATE){
handleDriverEvent(eventData);
}else{
handleEvent(event,eventData);//对于CONNECTED和DISCONNECTED等netlink事件将执行此操作来处理[luther.gliethttp]
// If supplicant is gone, exit the thread
if(event==TERMINATING){
break;
}
}
...
voidhandleEvent(intevent,Stringremainder){
switch(event){
caseDISCONNECTED:
handleNetworkStateChange(NetworkInfo.DetailedState.DISCONNECTED,remainder);
break;
caseCONNECTED:
handleNetworkStateChange(NetworkInfo.DetailedState.CONNECTED,remainder);//控制界面显示
break;
...
}
publicclassWifiStateTrackerextendsNetworkStateTracker{
...
publicvoidstartEventLoop(){
mWifiMonitor.startMonitoring();//启动上面的MonitorThread线程
}
...
}
java/services/com/android/server/WifiService.java
publicclassWifiServiceextendsIWifiManager.Stub{
...
privatebooleansetWifiEnabledBlocking(booleanenable){
finalinteventualWifiState=enable?WIFI_STATE_ENABLED:WIFI_STATE_DISABLED;
...
if(enable){
if(WifiNative.loadDriver()){
Log.e(TAG,"Failed to load Wi-Fi driver.");
updateWifiState(WIFI_STATE_UNKNOWN);
returnfalse;
}
if(WifiNative.startSupplicant()){
WifiNative.unloadDriver();
Log.e(TAG,"Failed to start supplicant daemon.");
updateWifiState(WIFI_STATE_UNKNOWN);
returnfalse;
}
mWifiStateTracker.startEventLoop();
//启动MonitorThread线程,等待wpa_supplicant将netlink数据转发过来,然后根据netlink动作类型,进一步影响界面显示[luther.gliethttp].
}
...
}
java/android/android/net/wifi/WifiStateTracker.java
电源管理
privatevoidhandleConnectedState(){
...
mDhcpTarget.obtainMessage(EVENT_DHCP_START).sendToTarget();//传递到下面的handleMessage方法
...
}
publicvoidonChange(booleanselfChange){
...
handleConnectedState();
...
}
publicclassWifiStateTrackerextendsNetworkStateTracker{
...
publicvoidhandleMessage(Message msg){
switch(msg.what){
caseEVENT_SUPPLICANT_CONNECTION:
caseEVENT_NETWORK_STATE_CHANGED:
handleConnectedState();//调用
...
privateclassDhcpHandlerextendsHandler{
privateHandlermTarget;
publicDhcpHandler(Looper looper,Handlertarget){
super(looper);
mTarget=target;
}
publicvoidhandleMessage(Message msg){
intevent;
//private static final int DRIVER_POWER_MODE_AUTO = 0;
//private static final int DRIVER_POWER_MODE_ACTIVE = 1;
switch(msg.what){
caseEVENT_DHCP_START:
synchronized(this){
WifiNative.setPowerModeCommand(DRIVER_POWER_MODE_ACTIVE);//设置电源模式,调用android_net_wifi_setPowerModeCommand
}
Log.d(TAG,"DhcpHandler: DHCP request started");
//libs/android_runtime/android_net_NetUtils.cpp
//static JNINativeMethod gNetworkUtilMethods[] = {
//{ "runDhcp", "(Ljava/lang/String;Landroid/net/DhcpInfo;)Z", (void *)android_net_utils_runDhcp },
// ...
//};
if(NetworkUtils.runDhcp(mInterfaceName,mDhcpInfo)){//执行dhcp申请ip地址操作
event=EVENT_INTERFACE_CONFIGURATION_SUCCEEDED;
if(LOCAL_LOGD)Log.v(TAG,"DhcpHandler: DHCP request succeeded");
}else{
event=EVENT_INTERFACE_CONFIGURATION_FAILED;
Log.i(TAG,"DhcpHandler: DHCP request failed: "+
NetworkUtils.getDhcpError());
//如果dhcpcd分配ip失败,那么Message.obtain(mTarget, event).sendToTarget();将执行
//WifiNative.disconnectCommand();即:static JNINativeMethod gWifiMethods[] = {
//android_net_wifi_disconnectCommand发送"DISCONNECT"字符串[luther.gliethttp]
//然后在wpa_supplicant服务端执行wpa_supplicant_ctrl_iface_process
//wpa_supplicant_disassociate
}
synchronized(this){
WifiNative.setPowerModeCommand(DRIVER_POWER_MODE_AUTO);
}
Message.obtain(mTarget,event).sendToTarget();
break;
}
}
}
...
/**
* Send the tracker a notification that a connection to the supplicant
* daemon has been established.
*/
//在上面的public class WifiMonitor=>ensureSupplicantConnection
//=>
//while (!supplicantConnected) {
// boolean connected;
//synchronized (mWifiStateTracker) {
//connected = WifiNative.connectToSupplicant();//如果没有连接成功,那么while循环尝试,直到尝试成功,或者定义了oneShot,仅一次尝试
//=>mWifiStateTracker.notifySupplicantConnection();//如果WifiNative.connectToSupplicant()成功,那么将执行
//mWifiStateTracker.notifySupplicantConnection();的调用.
voidnotifySupplicantConnection(){//向对象发送message
Message.obtain(this,EVENT_SUPPLICANT_CONNECTION).sendToTarget();
}
voidnotifyStateChange(SupplicantState newState){
Message.obtain(this,EVENT_SUPPLICANT_STATE_CHANGED,newState).sendToTarget();
}
...
}
staticjboolean android_net_wifi_setPowerModeCommand(JNIEnv*env,jobject clazz,jint mode)
{
charcmdstr[256];
sprintf(cmdstr,"DRIVER POWERMODE %d",mode);
returndoBooleanCommand(cmdstr,"OK");
}
android_net_wifi_setPowerModeCommand
=>doBooleanCommand
=>doCommand
=>wifi_command
=>wifi_send_command
=>wpa_ctrl_request
=>send给wpa_supplicant
然后wpa_supplicant将做如下接收操作:
system/extra/wpa_supplicant/main.c
=>wpa_supplicant_add_iface
=>wpa_supplicant_init_iface2
=>wpa_supplicant_ctrl_iface_init
=>注册ctrl_conn控制端口和monitor_conn监听端口的处理函数
eloop_register_read_sock(priv->sock,wpa_supplicant_ctrl_iface_receive,wpa_s,priv);//ctrl_conn端口的handler处理函数
wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);//monitor_conn端口的回调处理函数,处理netlink数据到所有monitor_conn监听端口
=>wpa_supplicant_ctrl_iface_receive//对于unix通信方式
=>wpa_supplicant_ctrl_iface_process
=>如果wpa_cli发送的是wpa_clidriverxxx形式的命令,那么调用这个函数
if(os_strncmp(buf,"DRIVER ",7)==0){//掠过前7个,直接将命令传过去
reply_len=wpa_supplicant_driver_cmd(wpa_s,buf+7,reply,reply_size);
=>wpa_supplicant_driver_cmd
=>wpa_drv_driver_cmd
=>自定义DRIVER扩展处理函数,所以对于java传递过来的power电源管理命令,wpa_drv_driver_cmd将收到"POWERMODE 0"或者"POWERMODE 1"字符串[luther.gliethttp]
=============================================================================================================
jni
=>runDhcp
=>android_net_utils_runDhcp
libs/netutils/dhcp_utils.c
=>dhcp_do_request
=>
staticconstcharDAEMON_NAME[]="dhcpcd";
staticconstcharDAEMON_PROP_NAME[]="init.svc.dhcpcd";
staticconstcharDHCP_PROP_NAME_PREFIX[]="dhcp";
constchar*ctrl_prop="ctl.start";
constchar*desired_status="running";
snprintf(result_prop_name,sizeof(result_prop_name),"%s.%s.result",
DHCP_PROP_NAME_PREFIX,
interface);
property_set(result_prop_name,"");//设置dhcp.eth0.result="";等到成功完成dhcp之后,
property_set(ctrl_prop,DAEMON_NAME);//向名字为dhcpcd的service,发送"ctrl.start"启动命令字,该service在init.rc中
//init.rc中dhcpcd服务进程命令字
//service dhcpcd /system/bin/dhcpcd eth0
// disabled
// oneshot
wait_for_property(DAEMON_PROP_NAME,desired_status,10);
//init.c=>init进程
//=>handle_property_set_fd因为是"ctrl.start"命令字,所以调用handle_control_message处理控制信息
//=>handle_control_message
//=>msg_start
//=>
// struct service *svc = service_find_by_name(name);
// service_start(svc);//启动svc,即执行:/system/bin/dhcpcd eth0
//=>service_start
//=>pid = fork();
// if(pid == 0)execve(svc->args[0], (char**) svc->args, (char**) ENV);子进程执行execve运行/system/bin/dhcpcd,参数为eth0
//=>否则父进程,即init进程将
//=>notify_service_state(svc->name, "running");设置该svc的状态prop
// snprintf(pname, sizeof(pname), "init.svc.%s", name);
// property_set(pname, state);//所以这样上面wait_for_property(DAEMON_PROP_NAME, desired_status, 10);也才能够正常pass[luther.gliethttp].
wait_for_property(result_prop_name,NULL,15);//等待dhcp.eth0.result=非空
=============================================================================================================
system/extra/dhcpcd-4.0.0-beta9/dhcpcd.c
dhcpcd
=>main
# define SYSCONFDIR"/system/etc/dhcpcd"
#definePACKAGE"dhcpcd"
# defineCONFIGSYSCONFDIR"/"PACKAGE".conf"
# define LIBEXECDIR"/system/etc/dhcpcd"
# define SCRIPTLIBEXECDIR"/"PACKAGE"-run-hooks"
=>strlcpy(options->script,SCRIPT,sizeof(options->script));//默认的options->script="/system/etc/dhcpcd/dhcpcd-run-hooks"
=>f=fopen(cf?cf:CONFIG,"r");//如果没有指定.conf文件,那么使用默认.conf文件
=>parse_config_line//解析"/system/etc/dhcpcd/dhcpcd.conf"默认配置文件
=>parse_option
=>如果在"/system/etc/dhcpcd/dhcpcd.conf"有"script"这个节
=>那么执行strlcpy(options->script,oarg,sizeof(options->script));直接拷贝
/*
{"script", required_argument, NULL, 'c'},
{"option", required_argument, NULL, 'o'},
"/system/etc/dhcpcd/dhcpcd.conf"中的部分内容如下:
...
option domain_name_servers, domain_name, domain_search, host_name
...
*/
=>dhcp_run
=>handle_dhcp_packet
=>handle_dhcp
=>bind_dhcp
reason="TIMEOUT";reason="BOUND";reason="REBIND";reason="RENEW";
system/extra/dhcpcd-4.0.0-beta9/configure.c
=>configure(iface,reason,state->new,state->old,&state->lease,options,1);
//如果dhcp超时或者dhcp成功,都会调用exec_script来执行脚本,
//执行setprop dhcp.${interface}.result "failed"或者
//执行setprop dhcp.${interface}.result "ok"
=>exec_script(options,iface->name,reason,NULL,old);
=>然后configure_env通过环境变量将reason传递到脚本中
intexec_script(conststructoptions*options,constchar*iface,constchar*reason,
conststructdhcp_message*dhcpn,conststructdhcp_message*dhcpo)
=>pid=fork();
=>if(pid==0)execve(options->script,argv,env);//子进程执行脚本,默认"/system/etc/dhcpcd/dhcpcd-run-hooks"
//dhcpcd-run-hooks脚本会根据level值,决定是否执行system/etc/dhcpcd/dhcpcd-hook/*目录下的相应文件
//我们的系统在该system/etc/dhcpcd/dhcpcd-hook/*目录下有如下3个文件
//95-configured
//20-dns.conf
//01-test
=>父进程返回while(waitpid(pid,&status,0)==-1)等待子进程脚本执行完成
system/extra/dhcpcd-4.0.0-beta9/dhcpcd-hooks/20-dns.conf
system/extra/dhcpcd-4.0.0-beta9/dhcpcd-hooks/95-configured
...
setprop dhcp.${interface}.ipaddress"${new_ip_address}"
setprop dhcp.${interface}.result"ok"//设置属性为ok
setprop dhcp.${interface}.result"failed"
...
=============================================================================================================
inet_init、tcp_prot
sock->ops->sendmsg(iocb,sock,msg,size);
=>inetsw_array[]
=>inet_stream_ops
=>tcp_sendmsg
=============================================================================================================
wpa_cli.c
=>main
=>wpa_cli_interactive
=>wpa_cli_recv_pending(monitor_conn,0,0);//阻塞等待wpa_supplicant发送数据过来
=>如果action_monitor为true,那么将执行一些简单加工操作,否则将直接将wpa_supplicant发过来的数据打印到console上[luther.gliethttp].