3034|0

853

帖子

0

TA的资源

五彩晶圆(中级)

楼主
 

淺析android下如何通過jni監控wifi網絡連接、dhcpcd執行和power電源控制 [复制链接]

  • 轉載的:http://blog.chinaunix.net/u1/38994/showart_1274854.html
      淺析android下如何通過jni監控wifi網絡連接、dhcpcd執行和power電源控制
      =============================================================================================================
      libs/android_runtime/android_net_wifi_Wifi.cpp
      部分jni接口
      static JNINativeMethod 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 },
       ...
      };
      int register_android_net_wifi_WifiManager(JNIEnv* env)
      {
       ...
       return AndroidRuntime::registerNativeMethods(env,
       WIFI_PKG_NAME, gWifiMethods, NELEM(gWifiMethods));//登記jni
      }
      libs/android_runtime/AndroidRuntime.cpp
      static const RegJNIRec gRegJNI[] = {
       ...
       REG_JNI(register_android_net_wifi_WifiManager),
       ...
      };
      int AndroidRuntime::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
      public class WifiMonitor {
       ...
       public void startMonitoring() {
       new MonitorThread().start();//啓動java線程
       }
       class MonitorThread extends Thread {
       public MonitorThread() {
       super("WifiMonitor");
       }
       public void run() {
       for (;;) {
       ensureSupplicantConnection();//=>WifiNative.connectToSupplicant調用jni函數android_net_wifi_connectToSupplicant
       String eventStr = 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";
       String eventName = eventStr.substring(eventPrefixLen);//去掉"CTRL-EVENT-"字符串
       int nameEnd = eventName.indexOf(' ');//找到隨後的空格位置,這在wpa_supplicant發送時
      //#define WPA_EVENT_CONNECTED "CTRL-EVENT-CONNECTED "中,已經內置空格了.
       if (nameEnd != -1)
       eventName = eventName.substring(0, nameEnd);
       int event;
       if (eventName.equals(connectedEvent))//檢測netlink過來的字符串action類型
       event = CONNECTED;
       else if (eventName.equals(disconnectedEvent))
       event = DISCONNECTED;
       ...
       int ind = eventStr.indexOf(" - ");//CTRL-EVENT-CONNECTED - Connection to ...
       if (ind != -1)
       eventData = eventStr.substring(ind + 3);
      //剔除前導控制字符,將" - "後面的描述字符串作爲真實數據,繼續處理
       ...
       if (event == STATE_CHANGE) {
       handleSupplicantStateChange(eventData);
       } else if (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;
       }
       }
       ...
       void handleEvent(int event, String remainder) {
       switch (event) {
       case DISCONNECTED:
       handleNetworkStateChange(NetworkInfo.DetailedState.DISCONNECTED, remainder);
       break;
       case CONNECTED:
       handleNetworkStateChange(NetworkInfo.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 setWifiEnabledBlocking(boolean enable) {
       final int eventualWifiState = 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);
       return false;
       }
       if (WifiNative.startSupplicant()) {
       WifiNative.unloadDriver();
       Log.e(TAG, "Failed to start supplicant daemon.");
       updateWifiState(WIFI_STATE_UNKNOWN);
       return false;
       }
       mWifiStateTracker.startEventLoop();
      //啓動MonitorThread線程,等待wpa_supplicant將netlink數據轉發過來,然後根據netlink動作類型,進一步影響界面顯示[luther.gliethttp].
       }
       ...
      }
      java/android/android/net/wifi/WifiStateTracker.java
      電源管理
      private void handleConnectedState() {
       ...
       mDhcpTarget.obtainMessage(EVENT_DHCP_START).sendToTarget();//傳遞到下面的handleMessage方法
       ...
      }
      public void onChange(boolean selfChange) {
       ...
       handleConnectedState();
       ...
      }
      public class WifiStateTracker extends NetworkStateTracker {
       ...
       public void handleMessage(Message msg) {
       switch (msg.what) {
       case EVENT_SUPPLICANT_CONNECTION:
       case EVENT_NETWORK_STATE_CHANGED:
       handleConnectedState();//調用
       ...
       private class DhcpHandler extends Handler {
       private Handler mTarget;
       public DhcpHandler(Looper looper, Handler target) {
       super(looper);
       mTarget = target;
       }
       public void handleMessage(Message 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.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();的調用.
       void notifySupplicantConnection() {//向對象發送message
       Message.obtain(this, EVENT_SUPPLICANT_CONNECTION).sendToTarget();
       }
       void notifyStateChange(SupplicantState newState) {
       Message.obtain(this, EVENT_SUPPLICANT_STATE_CHANGED, newState).sendToTarget();
       }
       ...
      }
      static jboolean android_net_wifi_setPowerModeCommand(JNIEnv* env, jobject clazz, jint mode)
      {
       char cmdstr[256];
       sprintf(cmdstr, "DRIVER POWERMODE %d", mode);
       return doBooleanCommand(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_cli driver xxx形式的命令,那麽調用這個函數
      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
      =>
       static const char DAEMON_NAME[] = "dhcpcd";
       static const char DAEMON_PROP_NAME[] = "init.svc.dhcpcd";
       static const char DHCP_PROP_NAME_PREFIX[] = "dhcp";
       const char *ctrl_prop = "ctl.start";
       const char *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"
      #define PACKAGE "dhcpcd"
      # define CONFIG SYSCONFDIR "/" PACKAGE ".conf"
      # define LIBEXECDIR "/system/etc/dhcpcd"
      # define SCRIPT LIBEXECDIR "/" 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"或者
      //執行setpro



点赞 关注
个人签名如果对linux,Android,wince 等嵌入式底层有兴趣的,请加这个QQ群吧,群号:27100460

回复
举报
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条
有奖直播报名| TI 面向楼宇和工厂自动化行业的毫米波雷达解决方案
【内容简介】TI 60GHz IWRL6432和 IWRL1432毫米波雷达传感器如何帮助解决楼宇和工厂自动化应用中的感应难题
【直播时间】5月28日(周三)上午10:00
【直播礼品】小米双肩包、contigo水杯、胶囊伞、安克充电器

查看 »

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网 14

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表