【Android论文栏目提醒】:本文主要为网学会员提供“浅析android下如何通过jni监控wifi网络连接、dhcpcd执行和power - 电子设计”,希望对需要浅析android下如何通过jni监控wifi网络连接、dhcpcd执行和power - 电子设计网友有所帮助,学习一下!
浅析android下如何通过jni监控wifi网络连接、dhcpcd执行和power电源控制 libs/android_runtime/android_net_wifi_Wifi.cpp 部分jni接口 st - 浅析android下如何通过jni监控wifi网络连接、dhcpcd执行和power电源控制 libs/android_runtime/android_net_wifi_Wifi.cpp 部分jni接口 static JNINativeMethod gWifiMethods quotloadDriverquot quotZquot void android_net_wifi_loadDriver quotsetPowerModeCommandquot quotIZquot void android_net_wifi_setPowerModeCommand //电源管理 quotconnectToSupplicantquot quotZquot void android_net_wifi_connectToSupplicant quotwaitForEventquot quotLjava/lang/Stringquot void android_net_wifi_waitForEvent quotdisconnectCommandquot quotZquot void android_net_wifi_disconnectCommand ... int register_android_net_wifi_WifiManagerJNIEnv env ... return AndroidRuntime::registerNativeMethodsenv WIFI_PKG_NAME gWifiMethods NELEMgWifiMethods//登记jni libs/android_runtime/AndroidRuntime.cpp static const RegJNIRec gRegJNI ... REG_JNIregister_android_net_wifi_WifiManager ... int AndroidRuntime::startRegJNIEnv env ... register_jni_procsgRegJNI NELEMgRegJNI env ... AndroidRuntime::start gtstartRegenv即调用方法int AndroidRuntime::startRegJNIEnv env wifi_load_driver wifi_start_supplicant gtensure_config_file_exists //检查/data/misc/wifi/wpa_supplicant.conf文件是否存在如果不存在那么从/system/etc/wifi/wpa_supplicant.conf动态拷贝一份 android_net_wifi_connectToSupplicant gtwifi_connect_to_supplicant gt ctrl_conn wpa_ctrl_openifname monitor_conn wpa_ctrl_openifname wpa_ctrl_attachmonitor_conn android_net_wifi_waitForEvent gtwifi_wait_for_event gtwpa_ctrl_recvmonitor_conn buf ampnread gtrecvctrl-gts reply reply_len 0//阻塞等待wpa_supplicant的netlink数据过来 gt如果接收的buf数据区buf0为lt那么说明有level级别信息所以将lt...gt数据剔除然后wifi_wait_for_event函数返回luther.gliethttp. java/android/android/net/wifi/WifiMonitor.java public class WifiMonitor ... public void startMonitoring new MonitorThread.start//启动java线程 class MonitorThread extends Thread public MonitorThread superquotWifiMonitorquot public void run for ensureSupplicantConnection//gtWifiNative.connectToSupplicant调用jni函数android_net_wifi_connectToSupplicant String eventStr WifiNative.waitForEvent//gt调用jni函数android_net_wifi_waitForEvent //private static final int CONNECTED 1 //private static final int DISCONNECTED 2 //private static final String eventPrefix quotCTRL-EVENT-quot //private static final int eventPrefixLen eventPrefix.length //private static final String connectedEvent quotCONNECTEDquot //private static final String disconnectedEvent quotDISCONNECTEDquot String eventName eventStr.substringeventPrefixLen//去掉quotCTRL-EVENT-quot字符串 int nameEnd eventName.indexOf //找到随后的空格位置这在wpa_supplicant发送时 //define WPA_EVENT_CONNECTED quotCTRL-EVENT-CONNECTED quot中已经内置空格了. if nameEnd -1 eventName eventName.substring0 nameEnd int event if eventName.equalsconnectedEvent//检测netlink过来的字符串action类型 event CONNECTED else if eventName.equalsdisconnectedEvent event - eventName eventName.substring0 nameEnd int event if eventName.equalsconnectedEvent//检测netlink过来的字符串action类型 event CONNECTED else if eventName.equalsdisconnectedEvent event DISCONNECTED ... int ind eventStr.indexOfquot - quot//CTRL-EVENT-CONNECTED - Connection to ... if ind -1 eventData eventStr.substringind 3 //剔除前导控制字符将quot - quot后面的描述字符串作为真实数据继续处理 ... if event STATE_CHANGE handleSupplicantStateChangeeventData else if event DRIVER_STATE handleDriverEventeventData else handleEventevent eventData//对于CONNECTED和DISCONNECTED等netlink事件将执行此操作来处理luther.gliethttp // If supplicant is gone exit the thread if event TERMINATING break ... void handleEventint event String remainder switch event case DISCONNECTED: handleNetworkStateChangeNetworkInfo.DetailedState.DISCONNECTED remainder break case CONNECTED: handleNetworkStateChangeNetworkInfo.DetailedState.CONNECTED remainder//控制界面显示 break ... public class WifiStateTracker extends NetworkStateTracker ... public void startEventLoop mWifiMonitor.startMonitoring//启动上面的MonitorThread线程 ... java/services/com/android/server/WifiService.java public class WifiService extends IWifiManager.Stub ... private boolean setWifiEnabledBlockingboolean enable final int eventualWifiState enable WIFI_STATE_ENABLED : WIFI_STATE_DISABLED ... if enable if WifiNative.loadDriver Log.eTAG Failed to load Wi-Fi driver. updateWifiStateWIFI_STATE_UNKNOWN return false if WifiNative.startSupplicant WifiNative.unloadDriver Log.eTAG - if WifiNative.loadDriver Log.eTAG quotFailed to load Wi-Fi driver.quot updateWifiStateWIFI_STATE_UNKNOWN return false if WifiNative.startSupplicant WifiNative.unloadDriver Log.eTAG quotFailed to start supplicant daemon.quot updateWifiStateWIFI_STATE_UNKNOWN return false mWifiStateTracker.startEventLoop //启动MonitorThread线程等待wpa_supplicant将netlink数据转发过来然后根据netlink动作类型进一步影响界面显示luther.gliethttp. ... java/android/android/net/wifi/WifiStateTracker.java 电源管理 private void handleConnectedState ... mDhcpTarget.obtainMessageEVENT_DHCP_START.sendToTarget//传递到下面的handleMessage方法 ... public void onChangeboolean selfChange ... handleConnectedState ... public class WifiStateTracker extends NetworkStateTracker ... public void handleMessageMessage msg switch msg.what case EVENT_SUPPLICANT_CONNECTION: case EVENT_NETWORK_STATE_CHANGED: handleConnectedState//调用 ... private class DhcpHandler extends Handler private Handler mTarget public DhcpHandlerLooper looper Handler target superlooper mTarget target public void handleMessageMessage msg int event //private static final int DRIVER_POWER_MODE_AUTO 0 //private static final int DRIVER_POWER_MODE_ACTIVE 1 switch msg.what case EVENT_DHCP_START: synchronized this WifiNative.setPowerModeCommandDRIVER_POWER_MODE_ACTIVE//设置电源模式调用android_net_wifi_setPowerModeCommand Log.dTAG quotDhcpHandler: DHCP request startedquot //libs/android_runtime/android_net_NetUtils.cpp //static JNINativeMethod gNetworkUtilMethods // quotrunDhcpquot quotLjava/lang/StringLandroid/net/DhcpInfoZquot void android_net_utils_runDhcp // ... // if NetworkUtils.runDhcpmInterfaceName mDhcpInfo //执行dhcp申请ip地址操作 event EVENT_INTERFACE_CONFIGURATION_SUCCEEDED if LOCAL_LOGD Log.vTAG DhcpHandler: DHCP request succeeded else event EVENT_INTERFACE_CONFIGURATION_FAILED Log.iTAG DhcpHandler: DHCP request failed: NetworkUtils.getDhcpError // - if LOCAL_LOGD Log.vTAG quotDhcpHandler: DHCP request succeededquot else event EVENT_INTERFACE_CONFIGURATION_FAILED Log.iTAG quotDhcpHandler: DHCP request failed: quot NetworkUtils.getDhcpError //如果dhcpcd分配ip失败那么Message.obtainmTarget event.sendToTarget将执行 //WifiNative.disconnectCommand即static JNINativeMethod gWifiMethods //android_net_wifi_disconnectCommand发送quotDISCONNECTquot字符串luther.gliethttp //然后在wpa_supplicant服务端执行wpa_supplicant_ctrl_iface_process //wpa_supplicant_disassociate synchronized this WifiNative.setPowerModeCommandDRIVER_POWER_MODE_AUTO Message.obtainmTarget event.sendToTarget break ... / Send the tracker a notification that a connection to the supplicant daemon has been established. / //在上面的public class WifiMonitorgtensureSupplicantConnection //gt //while supplicantConnected // boolean connected //synchronized mWifiStateTracker //connected WifiNative.connectToSupplicant//如果没有连接成功那么while循环尝试直到尝试成功或者定义了oneShot仅一次尝试 //gtmWifiStateTracker.notifySupplicantConnection//如果WifiNative.connectToSupplicant成功那么将执行 //mWifiStateTracker.notifySupplicantConnection的调用. void notifySupplicantConnection //向对象发送message Message.obtainthis EVENT_SUPPLICANT_CONNECTION.sendToTarget void notifyStateChangeSupplicantState newState Message.obtainthis EVENT_SUPPLICANT_STATE_CHANGED newState.sendToTarget ... static jboolean android_net_wifi_setPowerModeCommandJNIEnv env jobject clazz jint mode char cmdstr256 sprintfcmdstr quotDRIVER POWERMODE dquot mode return doBooleanCommandcmdstr quotOKquot android_net_wifi_setPowerModeCommand gtdoBooleanCommand gtdoCommand gtwifi_command gtwifi_send_command gtwpa_ctrl_request gtsend给wpa_supplicant 然后wpa_supplicant将做如下接收操作 system/extra/wpa_supplicant/main.c gtwpa_supplicant_add_iface gtwpa_supplicant_init_iface2 gtwpa_supplicant_ctrl_iface_init gt注册ctrl_conn控制端口和monitor_conn监听端口的处理函数 eloop_register_read_sockpriv-gtsock wpa_supplicant_ctrl_iface_receive wpa_s priv//ctrl_conn端口的handler处理函数 wpa_msg_register_cbwpa_supplicant_ctrl_iface_msg_cb//monitor_conn端口的回调处理函数处理netlink数据到所有monitor_conn监听端口 gtwpa_supplicant_ctrl_iface_receive//对于unix通信方式 gtwpa_supplicant_ctrl_iface_process gt如果wpa_cli发送的是wpa_cli driver xxx形式的命令那么调用这个函数 if os_strncmpbuf quotDRIVER quot 7 0 //掠过前7个直接将命令传过去 reply_len wpa_supplicant_driver_cmdwpa_s buf 7 reply reply_size gtwpa_supplicant_driver_cmd wpa_drv_driver_cmd 自定义DRIVER扩展处理函数所以对于java传递过来的power电源管理命令wpa_drv_driver_cmd将收到POWERMODE 0或者POWERMODE 1字符串luther.gliethttp - gtwpa_drv_driver_cmd gt自定义DRIVER扩展处理函数所以对于java传递过来的power电源管理命令wpa_drv_driver_cmd将收到quotPOWERMODE 0quot或者quotPOWERMODE 1quot字符串luther.gliethttp jni gtrunDhcp gtandroid_net_utils_runDhcp libs/netutils/dhcp_utils.c gtdhcp_do_request gt static const char DAEMON_NAME quotdhcpcdquot static const char DAEMON_PROP_NAME quotinit.svc.dhcpcdquot static const char DHCP_PROP_NAME_PREFIX quotdhcpquot const char ctrl_prop quotctl.startquot const char desired_status quotrunningquot snprintfresult_prop_name sizeofresult_prop_name quots.s.resultquot DHCP_PROP_NAME_PREFIX interface property_setresult_prop_name quotquot//设置dhcp.eth0.resultquotquot等到成功完成dhcp之后 property_setctrl_prop DAEMON_NAME//向名字为dhcpcd的service发送quotctrl.startquot启动命令字该service在init.rc中 //init.rc中dhcpcd服务进程命令字 //service dhcpcd /system/bin/dhcpcd eth0 // disabled // oneshot wait_for_propertyDAEMON_PROP_NAME desired_status 10 //init.cgtinit进程 //gthandle_property_set_fd因为是quotctrl.startquot命令字所以调用handle_control_message处理控制信息 //gthandle_control_message //gtmsg_start //gt // struct service svc service_find_by_namename // service_startsvc//启动svc即执行/system/bin/dhcpcd eth0 //gtservice_start //gtpid fork // ifpid 0execvesvc-gtargs0 char svc-gtargs char ENV子进程执行execve运行/system/bin/dhcpcd参数为eth0 //gt否则父进程即init进程将 //gtnotify_service_statesvc-gtname quotrunningquot设置该svc的状态prop // snprintfpname sizeofpname quotinit.svc.squot name // property_setpname state//所以这样上面wait_for_propertyDAEMON_PROP_NAME desired_status 10也才能够正常passluther.gliethttp. wait_for_propertyresult_prop_name NULL 15//等待dhcp.eth0.result非空 system/extra/dhcpcd-4.0.0-beta9/dhcpcd.c dhcpcd gtmain define SYSCONFDIR quot/system/etc/dhcpcdquot define PACKAGE quotdhcpcdquot define CONFIG SYSCONFDIR quot/quot PACKAGE quot.confquot define LIBEXECDIR quot/system/etc/dhcpcdquot define SCRIPT LIBEXECDIR quot/quot PACKAGE quot-run-hooksquot gtstrlcpyoptions-gtscript SCRIPT sizeofoptions-gtscript//默认的options-gtscriptquot/system/etc/dhcpcd /dhcpcd-run-hooksquot gtf fopencf cf : CONFIG quotrquot//如果没有指定.conf文件那么使用默认.conf文件 gtparse_config_line//解析quot/system/etc/dhcpcd/dhcpcd.confquot默认配置文件 gtparse_option gt如果在quot/system/etc/dhcpcd/dhcpcd.confquot有quotscriptquot这个节 gt那么执行strlcpyoptions-gtscript oarg sizeofoptions-gtscript直接拷贝 / quotscriptquot required_argument NULL c quotoptionquot required_argument NULL o quot/system/etc/dhcpcd/dhcpcd.confquot中的部分内容如下 ... option domain_name_servers domain_name domain_search host_name ... / gtdhcp_run gthandle_dhcp_packet gthandle_dhcp gtbind_dhcp reason quotTIMEOUTquotreason quotBOUNDquotreason quotREBINDquotreason quotRENEWquot system/extra/dhcpcd-4.0.0-beta9/configure.c gt configureiface reason state-gtnew state-gtold ampstate-gtlease options 1 //如果dhcp超时或者dhcp成功都会调用exec_script来执行脚本 //执行setprop dhcp.interface.result quotfailedquot或者 //执行setprop dhcp.interface.result quotokquot gtexec_scriptoptions iface-gtname reason NULL old gt然后configure_env通过环境变量将reason传递到脚本中 int exec_scriptconst struct options options const char iface const char reason const struct dhcp_message dhcpn const struct dhcp_message dhcpo pid fork ifpid 0execveoptions-script argv env//子进程执行脚本默认/system/etc/dhcpcd/dhcpcd-run-hooks //dhcpcd-run-hooks脚本会根据level值决定是否执行system/etc/dhcpcd/dhcpcd-hook/ - gtpid fork gtifpid 0execveoptions-gtscript argv env//子进程执行脚本默认quot/system/etc/dhcpcd/dhcpcd-run-hooksquot //dhcpcd-run-hooks脚本会根据level值决定是否执行system/etc/dhcpcd/dhcpcd-hook/目录下的相应文件 //我们的系统在该system/etc/dhcpcd/dhcpcd-hook/目录下有如下3个文件 //95-configured //20-dns.conf //01-test gt父进程返回while waitpidpid ampstatus 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 quotnew_ip_addressquot setprop dhcp.interface.result quotokquot//设置属性为ok setprop dhcp.interface.result quotfailedquot ... .