การวิเคราะห์โดยย่อเกี่ยวกับวิธีตรวจสอบการเชื่อมต่อเครือข่าย wifi การดำเนินการ dhcpcd และการควบคุมแหล่งจ่ายไฟผ่าน jni ภายใต้ Android
================================================== ================================================== =========
libs/android_runtime/android_net_wifi_Wifi.cpp
ส่วนหนึ่งของอินเทอร์เฟซ jni
JNINativeMethod แบบคงที่ gWifiMethods [] = {
{ "loadDriver", "()Z", (เป็นโมฆะ *)android_net_wifi_loadDriver },
{ "setPowerModeCommand", "(I)Z", (เป็นโมฆะ*) android_net_wifi_setPowerModeCommand } // การจัดการพลังงาน
{ "connectToSupplicant", "()Z", (เป็นโมฆะ *)android_net_wifi_connectToSupplicant },
{ "waitForEvent", "()Ljava/lang/String;", (เป็นโมฆะ*) android_net_wifi_waitForEvent },
{ "disconnectCommand", "()Z", (เป็นโมฆะ *)android_net_wifi_disconnectCommand },
-
-
int register_android_net_wifi_WifiManager (JNIEnv * env)
-
-
ส่งคืน AndroidRuntime::registerNativeMethods (env,
WIFI_PKG_NAME, gWifiMethods, NELEM(gWifiMethods));//ลงทะเบียน jni
-
libs/android_runtime/AndroidRuntime.cpp
const RegJNIRec gRegJNI[] = {
-
REG_JNI(register_android_net_wifi_WifiManager)
-
-
int AndroidRuntime::startReg(JNIEnv* env)
-
-
register_jni_procs(gRegJNI, NELEM(gRegJNI), env);
-
-
รันไทม์ของ Android::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);//การบล็อกและรอข้อมูล netlink ของ wpa_supplicant เข้ามา
=>หากอยู่ในพื้นที่ข้อมูล buf ที่ได้รับ buf[0] คือ '<' หมายความว่ามีข้อมูลระดับ ดังนั้นข้อมูล '<'...'>' จะถูกลบออก จากนั้นฟังก์ชัน wifi_wait_for_event จะส่งคืน [luther. gliethttp]
java/android/android/net/wifi/WifiMonitor.java
WifiMonitor ระดับสาธารณะ {
-
โมฆะสาธารณะ startMonitoring () {
ใหม่ MonitorThread().start();//เริ่มเธรด java
-
คลาส MonitorThread ขยายเธรด {
MonitorThread สาธารณะ () {
ซุปเปอร์("WifiMonitor");
-
โมฆะสาธารณะวิ่ง () {
สำหรับ (;;) {
ให้แน่ใจว่า SupplicantConnection();//=>WifiNative.connectToSupplicant เรียกใช้ฟังก์ชัน jni android_net_wifi_connectToSupplicant
String eventStr = WifiNative.waitForEvent();//=>เรียกใช้ฟังก์ชัน jni android_net_wifi_waitForEvent
// int สุดท้ายคงที่ส่วนตัว CONNECTED = 1;
// int สุดท้ายคงที่ส่วนตัว DISCONNECTED = 2;
//private static สุดท้าย String eventPrefix = "CTRL-EVENT-";
// ส่วนตัว int สุดท้ายคงที่ eventPrefixLen = eventPrefix.length ();
// ส่วนตัวคงที่สุดท้าย String เชื่อมต่อกิจกรรม = "เชื่อมต่อ";
//private static สุดท้าย String ถูกตัดการเชื่อมต่อEvent = "DICONNECTED";
String eventName = eventStr.substring(eventPrefixLen);//ลบสตริง "CTRL-EVENT-"
int nameEnd = eventName.indexOf(' ');//ค้นหาตำแหน่งช่องว่างถัดไป ซึ่งเป็นเวลาที่ส่ง wpa_supplicant
//#define WPA_EVENT_CONNECTED "CTRL-EVENT-CONNECTED" มีช่องว่างในตัว
ถ้า (nameEnd != -1)
eventName = eventName.substring(0, ชื่อสิ้นสุด);
เหตุการณ์ภายใน;
ถ้า (eventName.equals(connectedEvent))//ตรวจหาประเภทการกระทำของสตริงจาก netlink
เหตุการณ์ = เชื่อมต่อ;
อย่างอื่นถ้า (eventName.equals(disconnectedEvent))
เหตุการณ์ = ตัดการเชื่อมต่อ;
-
int ind = eventStr.indexOf(" - ");//CTRL-EVENT-CONNECTED - การเชื่อมต่อกับ ...
ถ้า (ระบุ != -1)
eventData = eventStr.substring (ind + 3);
//ลบอักขระควบคุมนำหน้าออก ใช้สตริงคำอธิบายหลัง "-" เป็นข้อมูลจริง และดำเนินการประมวลผลต่อไป
-
ถ้า (เหตุการณ์ == STATE_CHANGE) {
handleSupplicantStateChange (ข้อมูลเหตุการณ์);
} อื่นถ้า (เหตุการณ์ == DRIVER_STATE) {
handleDriverEvent (ข้อมูลเหตุการณ์);
} อื่น {
handleEvent(event, eventData);//สำหรับเหตุการณ์ netlink เช่น CONNECTED และ DISCONNECTED การดำเนินการนี้จะดำเนินการเพื่อจัดการ [luther.gliethttp]
// หากผู้ร้องขอหายไป ให้ออกจากเธรด
ถ้า (เหตุการณ์ == การยกเลิก) {
หยุดพัก;
-
-
-
เป็นโมฆะ handleEvent (เหตุการณ์ int, ส่วนที่เหลือของสตริง) {
สวิตช์ (เหตุการณ์) {
กรณีที่ถูกตัดการเชื่อมต่อ:
handleNetworkStateChange (NetworkInfo.DetailedState.DISCONNECTED, ส่วนที่เหลือ);
หยุดพัก;
กรณีเชื่อมต่อ:
handleNetworkStateChange (NetworkInfo.DetailedState.CONNECTED, ส่วนที่เหลือ); // จอแสดงผลอินเทอร์เฟซการควบคุม
หยุดพัก;
-
-
WifiStateTracker ระดับสาธารณะขยาย NetworkStateTracker {
-
โมฆะสาธารณะ startEventLoop() {
mWifiMonitor.startMonitoring();//เริ่มเธรด MonitorThread ด้านบน
-
-
-
java/services/com/android/server/WifiService.java
WifiService ระดับสาธารณะขยาย IWifiManager.Stub {
-
setWifiEnabledBlocking บูลีนส่วนตัว (เปิดใช้งานบูลีน) {
int สุดท้าย eventualWifiState = เปิดใช้งาน ? WIFI_STATE_ENABLED : WIFI_STATE_DISABLED;
-
ถ้า (เปิดใช้งาน) {
ถ้า (WifiNative.loadDriver()) {
Log.e(TAG, "ไม่สามารถโหลดไดรเวอร์ Wi-Fi");
อัปเดต WifiState (WIFI_STATE_UNKNOWN);
กลับเท็จ;
-
ถ้า (WifiNative.startSupplicant()) {
WifiNative.unloadDriver();
Log.e(TAG, "ไม่สามารถเริ่มดีมอนผู้ร้องขอได้");
อัปเดต WifiState (WIFI_STATE_UNKNOWN);
กลับเท็จ;
-
mWifiStateTracker.startEventLoop();
//เริ่มเธรด MonitorThread รอ wpa_supplicant ส่งต่อข้อมูล netlink จากนั้นส่งผลต่อการแสดงอินเทอร์เฟซเพิ่มเติมตามประเภทการกระทำของ netlink [luther.gliethttp]
-
-
-
java/android/android/net/wifi/WifiStateTracker.java
การจัดการพลังงาน
โมฆะส่วนตัว handleConnectedState () {
-
mDhcpTarget.obtainMessage(EVENT_DHCP_START).sendToTarget(); // ส่งผ่านไปยังวิธี handleMessage ด้านล่าง
-
-
โมฆะสาธารณะ onChange (การเปลี่ยนแปลงตนเองแบบบูลีน) {
-
handleConnectedState ();
-
-
WifiStateTracker ระดับสาธารณะขยาย NetworkStateTracker {
-
โมฆะสาธารณะ handleMessage (ข้อความข้อความ) {
สวิตช์ (ข้อความอะไร) {
กรณี EVENT_SUPPLICANT_CONNECTION:
กรณี EVENT_NETWORK_STATE_CHANGED:
handleConnectedState();//call
-
คลาสส่วนตัว DhcpHandler ขยายตัวจัดการ {
ตัวจัดการส่วนตัว mTarget;
DhcpHandler สาธารณะ (Looper looper, เป้าหมายตัวจัดการ) {
ซุปเปอร์(ลูปเปอร์);
mTarget = เป้าหมาย;
-
โมฆะสาธารณะ handleMessage (ข้อความข้อความ) {
เหตุการณ์ภายใน;
// ส่วนตัวคงที่สุดท้าย int DRIVER_POWER_MODE_AUTO = 0;
// ส่วนตัวคงที่สุดท้าย int DRIVER_POWER_MODE_ACTIVE = 1;
สวิตช์ (ข้อความอะไร) {
กรณี EVENT_DHCP_START:
ซิงโครไนซ์ (สิ่งนี้) {
WifiNative.setPowerModeCommand(DRIVER_POWER_MODE_ACTIVE);//ตั้งค่าโหมดพลังงานและเรียก android_net_wifi_setPowerModeCommand
-
Log.d(TAG, "DhcpHandler: คำขอ DHCP เริ่มต้นแล้ว");
//libs/android_runtime/android_net_NetUtils.cpp
// คง JNINativeMethod gNetworkUtilMethods [] = {
//{ "runDhcp", "(Ljava/lang/String;Landroid/net/DhcpInfo;)Z", (เป็นโมฆะ *)android_net_utils_runDhcp },
-
-
if (NetworkUtils.runDhcp(mInterfaceName, mDhcpInfo)) {//เรียกใช้แอปพลิเคชัน dhcp สำหรับการดำเนินการที่อยู่ IP
เหตุการณ์ = EVENT_INTERFACE_CONFIGURATION_SUCCEEDED;
ถ้า (LOCAL_LOGD) Log.v (TAG, "DhcpHandler: คำขอ DHCP สำเร็จ");
} อื่น {
เหตุการณ์ = EVENT_INTERFACE_CONFIGURATION_FAILED;
Log.i (TAG, "DhcpHandler: คำขอ DHCP ล้มเหลว: " +
NetworkUtils.getDhcpError());
//หาก dhcpcd ไม่สามารถจัดสรร IP ได้ Message.obtain(mTarget, event).sendToTarget(); จะถูกดำเนินการ
//WifiNative.disconnectCommand(); นั่นคือ: JNINativeMethod แบบคงที่ gWifiMethods[] = {
//android_net_wifi_disconnectCommand ส่งสตริง "DICONNECT" [luther.gliethttp]
//จากนั้นดำเนินการ wpa_supplicant_ctrl_iface_process บนเซิร์ฟเวอร์ wpa_supplicant
//wpa_supplicant_dissociate
-
ซิงโครไนซ์ (สิ่งนี้) {
WifiNative.setPowerModeCommand (DRIVER_POWER_MODE_AUTO);
-
Message.obtain(mTarget, เหตุการณ์).sendToTarget();
หยุดพัก;
-
-
-
-
-
* ส่งการแจ้งเตือนให้ติดตามว่ามีการเชื่อมต่อกับผู้ร้องขอ
* daemon ได้รับการจัดตั้งขึ้นแล้ว
-
//ในคลาสสาธารณะข้างต้น WifiMonitor=>ensureSupplicantConnection
-
// ในขณะที่ (! supplicantConnected) {
// เชื่อมต่อบูลีน;
// ซิงโครไนซ์ (mWifiStateTracker) {
//connected = WifiNative.connectToSupplicant();//หากการเชื่อมต่อไม่สำเร็จ ในขณะที่ลูปจะพยายามจนกว่าความพยายามจะสำเร็จ หรือกำหนด oneShot ไว้ ทำได้เพียงครั้งเดียวเท่านั้น
//=>mWifiStateTracker.notifySupplicantConnection();//หาก WifiNative.connectToSupplicant() สำเร็จ มันจะถูกดำเนินการ
//การเรียก mWifiStateTracker.notifySupplicantConnection();
เป็นโมฆะ notifySupplicantConnection() {//ส่งข้อความไปยังวัตถุ
Message.obtain (สิ่งนี้ EVENT_SUPPLICANT_CONNECTION). sendToTarget ();
-
เป็นโมฆะ notifyStateChange (SupplicantState newState) {
Message.obtain (สิ่งนี้ EVENT_SUPPLICANT_STATE_CHANGED, newState). sendToTarget ();
-
-
-
jboolean แบบคงที่ android_net_wifi_setPowerModeCommand (JNIEnv * env, jobject clazz, โหมด jint)
-
ถ่าน cmdstr [256];
sprintf(cmdstr, "โหมดขับเคลื่อนของไดรเวอร์ %d", โหมด);
กลับ doBooleanCommand(cmdstr, "ตกลง");
-
android_net_wifi_setPowerModeCommand
=>doBooleanCommand
=>ทำคำสั่ง
=>wifi_command
=>wifi_send_command
=>wpa_ctrl_request
=>ส่งไปที่ wpa_supplicant
จากนั้น wpa_supplicant จะดำเนินการรับดังต่อไปนี้:
ระบบ/พิเศษ/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
wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);//ฟังก์ชันการประมวลผลการเรียกกลับของพอร์ต monitor_conn ประมวลผลข้อมูล netlink ไปยังพอร์ตการฟังของ monitor_conn ทั้งหมด
=>wpa_supplicant_ctrl_iface_receive//สำหรับวิธีการสื่อสารแบบยูนิกซ์
=>wpa_supplicant_ctrl_iface_process
=>หาก wpa_cli ส่งคำสั่งในรูปแบบของ wpa_cli driver xxx ให้เรียกใช้ฟังก์ชันนี้
if (os_strncp(buf, "DRIVER ", 7) == 0) {//ข้าม 7 ตัวแรกและส่งคำสั่งโดยตรง
Reply_len = wpa_supplicant_driver_cmd(wpa_s, buf + 7, ตอบกลับ, Reply_size);
=>wpa_supplicant_driver_cmd
=>wpa_drv_driver_cmd
=> ปรับแต่งฟังก์ชันการประมวลผลส่วนขยาย DRIVER ดังนั้นสำหรับคำสั่งการจัดการพลังงานที่ส่งผ่านโดย java นั้น wpa_drv_driver_cmd จะได้รับสตริง "POWERMODE 0" หรือ "POWERMODE 1" [luther.gliethttp]
================================================== ================================================== =========
เจนี
=>runDhcp
=>android_net_utils_runDhcp
libs/netutils/dhcp_utils.c
=>dhcp_do_request
-
ถ่านคงที่ DAEMON_NAME[] = "dhcpcd";
ถ่านคงที่ DAEMON_PROP_NAME[] = "init.svc.dhcpcd";
ถ่านคงที่ DHCP_PROP_NAME_PREFIX[] = "dhcp";
const char *ctrl_prop = "ctl.start";
const char *desired_status = "กำลังทำงาน";
snprintf(result_prop_name, sizeof(result_prop_name), "%s.%s.result",
DHCP_PROP_NAME_PREFIX,
อินเตอร์เฟซ);
property_set(result_prop_name, "");//Set dhcp.eth0.result=""; รอจนกว่า dhcp จะเสร็จสมบูรณ์
property_set(ctrl_prop, DAEMON_NAME);//ส่งคำคำสั่งเริ่มต้น "ctrl.start" ไปยังบริการชื่อ dhcpcd ซึ่งอยู่ใน init.rc
//คำสั่งกระบวนการบริการ dhcpcd ใน init.rc
// บริการ dhcpcd /system/bin/dhcpcd eth0
// พิการ
//นัดเดียว
wait_for_property(DAEMON_PROP_NAME, ต้องการ_สถานะ, 10);
//init.c=>กระบวนการเริ่มต้น
//=>handle_property_set_fd คือคำคำสั่ง "ctrl.start" ดังนั้น handle_control_message จึงถูกเรียกเพื่อประมวลผลข้อความควบคุม
//=>handle_control_message
//=>msg_start
-
// บริการ struct *svc = service_find_by_name(name);
//service_start(svc);//เริ่ม svc นั่นคือดำเนินการ: /system/bin/dhcpcd eth0
//=>service_start
//=>pid = ส้อม();
// if(pid == 0)execve(svc->args[0], (char**) svc->args, (char**) ENV); กระบวนการลูกดำเนินการ execve และรัน /system/bin/dhcpcd , พารามิเตอร์สำหรับ eth0
//=>มิฉะนั้นกระบวนการหลัก นั่นคือ กระบวนการเริ่มต้นจะเกิดขึ้น
//=>notify_service_state(svc->name, "running"); ตั้งค่า state prop ของ svc
// snprintf(pname, sizeof(pname), "init.svc.%s", ชื่อ);
// property_set(pname, state);//ด้วยวิธีนี้ wait_for_property(DAEMON_PROP_NAME, Wish_status, 10); สามารถผ่าน [luther.gliethttp] ได้ตามปกติ
wait_for_property(result_prop_name, NULL, 15);//กำลังรอ dhcp.eth0.result=non-null
================================================== ================================================== =========
ระบบ/พิเศษ/dhcpcd-4.0.0-beta9/dhcpcd.c
dhcpcd
=>หลัก
#define SYSCONFDIR "/system/etc/dhcpcd"
#กำหนดแพ็คเกจ "dhcpcd"
# กำหนด CONFIG SYSCONFDIR "/" PACKAGE ".conf"
# กำหนด LIBEXECDIR "/system/etc/dhcpcd"
# กำหนด SCRIPT LIBEXECDIR "/" PACKAGE "-run-hooks"
=>strlcpy(options->script, SCRIPT, sizeof(options->script));//Default 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"
=>จากนั้นดำเนินการ strlcpy(options->script, oarg, sizeof(options->script)); คัดลอกโดยตรง
-
{"script", required_argument, NULL, 'c'},
{"ตัวเลือก", required_argument, NULL, 'o'},
ส่วนหนึ่งของเนื้อหาใน "/system/etc/dhcpcd/dhcpcd.conf" เป็นดังนี้:
-
ตัวเลือก domain_name_servers, domain_name, domain_search, host_name
-
-
=>dhcp_run
=>handle_dhcp_packet
=>handle_dhcp
=>bind_dhcp
เหตุผล = "หมดเวลา";เหตุผล = "ถูกผูกไว้";เหตุผล = "REBIND";เหตุผล = "ต่ออายุ";
ระบบ/พิเศษ/dhcpcd-4.0.0-beta9/configure.c
=> กำหนดค่า (iface, เหตุผล, state->new, state->old, &state->lease, options, 1);
//หาก dhcp หมดเวลาหรือ dhcp สำเร็จ exec_script จะถูกเรียกให้รันสคริปต์
//Execute setprop dhcp.${interface}.result "ล้มเหลว" หรือ
//ดำเนินการ setprop dhcp.${interface}.result "ตกลง"
=>exec_script(ตัวเลือก, iface->ชื่อ, เหตุผล, NULL, เก่า);
=>จากนั้น configuration_env จะส่งเหตุผลไปยังสคริปต์ผ่านตัวแปรสภาพแวดล้อม
int exec_script (ตัวเลือก const struct *ตัวเลือก, const char *iface, const char *เหตุผล
const struct dhcp_message *dhcpn, const struct dhcp_message *dhcpo)
=>pid = ส้อม();
=>if(pid == 0)execve(options->script, argv, env);//กระบวนการลูกดำเนินการสคริปต์ ค่าเริ่มต้นคือ "/system/etc/dhcpcd/dhcpcd-run-hooks"
//สคริปต์ dhcpcd-run-hooks จะตัดสินใจว่าจะดำเนินการไฟล์ที่เกี่ยวข้องในไดเร็กทอรี system/etc/dhcpcd/dhcpcd-hook/* ตามค่าระดับหรือไม่
//ระบบของเรามี 3 ไฟล์ต่อไปนี้ในไดเร็กทอรี system/etc/dhcpcd/dhcpcd-hook/*
//95-กำหนดค่าแล้ว
//20-dns.conf
//01-ทดสอบ
=>กระบวนการหลักส่งคืนในขณะที่ (waitpid(pid, &status, 0) == -1) และรอให้การประมวลผลสคริปต์กระบวนการลูกเสร็จสมบูรณ์
ระบบ/พิเศษ/dhcpcd-4.0.0-beta9/dhcpcd-hooks/20-dns.conf
ระบบ/พิเศษ/dhcpcd-4.0.0-beta9/dhcpcd-hooks/95-กำหนดค่าแล้ว
-
setprop dhcp.${interface}.ipaddress "${new_ip_address}"
setprop dhcp.${interface}.result "ok"//ตั้งค่าแอตทริบิวต์เป็น ok
setprop dhcp.${interface}. ผล "ล้มเหลว"
-
================================================== ================================================== =========
inet_init, tcp_prot
ถุงเท้า -> ops -> sendmsg (iocb, ถุงเท้า, ผงชูรส, ขนาด);
=>inetsw_array[]
=>inet_stream_ops
=>tcp_sendmsg
================================================== ================================================== =========
wpa_cli.c
=>หลัก
=>wpa_cli_interactive
=>wpa_cli_recv_pending(monitor_conn, 0, 0);//การบล็อกและรอ wpa_supplicant ส่งข้อมูล
=>หาก action_monitor เป็นจริง จะมีการดำเนินการประมวลผลง่ายๆ บางอย่าง มิฉะนั้นข้อมูลที่ส่งโดย wpa_supplicant จะถูกพิมพ์โดยตรงไปยังคอนโซล [luther.glethttp]