網上關於如何用代碼設置wifi的文章一搜一大堆,小蔣在此就再也不添亂了,我就試着給你們談一談wifi的源碼吧。 java
首先,我仍是得從代碼入手,下面是設置打開wifi的相關代碼: android
private WifiManager mWifiManager; public WifiAdmin(Context context){ //取得WifiManager對象 mWifiManager=(WifiManager)context.getSystemService(Context.WIFI_SERVICE); //取得WifiInfo對象 mWifiInfo=mWifiManager.getConnectionInfo(); } //打開wifi public void openWifi(){ if(!mWifiManager.isWifiEnabled()){ mWifiManager.setWifiEnabled(true); } }很簡單的一個函數--setWifiEnabled(ture),那咱們開始分析吧!
首先找到WifiManager.java(frameworks/base/wifi/java/android/net/wifi),裏面有 安全
public class WifiManager { IWifiManager mService; /** * Enable or disable Wi-Fi. * @param enabled {@code true} to enable, {@code false} to disable. * @return {@code true} if the operation succeeds (or if the existing state * is the same as the requested state). */ public boolean setWifiEnabled(boolean enabled) { try { return mService.setWifiEnabled(enabled); } catch (RemoteException e) { return false; } } }
IWifiManager也是什麼東西呢?在frameworks/base/wifi/java/android/net/wifi裏面你會發現一個叫作IWifiManager.aidl的文件 cookie
interface IWifiManager { boolean setWifiEnabled(boolean enable); }
這是一個aidl文件,若是有不懂的請看個人其餘文章,這個interface會在WifiService.java裏面實現(frameworks/base/services/java/com/android/server) app
/** * WifiService handles remote WiFi operation requests by implementing * the IWifiManager interface. It also creates a WifiMonitor to listen * for Wifi-related events. * * @hide */ public class WifiService extends IWifiManager.Stub { private final WifiHandler mWifiHandler; private Context mContext; private static PowerManager.WakeLock sWakeLock; /** * see {@link android.net.wifi.WifiManager#setWifiEnabled(boolean)} * @param enable {@code true} to enable, {@code false} to disable. * @return {@code true} if the enable/disable operation was * started or is already in the queue. */ public boolean setWifiEnabled(boolean enable) { enforceChangePermission(); if (mWifiHandler == null) return false; synchronized (mWifiHandler) { // caller may not have WAKE_LOCK permission - it's not required here long ident = Binder.clearCallingIdentity(); sWakeLock.acquire(); Binder.restoreCallingIdentity(ident); mLastEnableUid = Binder.getCallingUid(); // set a flag if the user is enabling Wifi while in airplane mode mAirplaneModeOverwridden = (enable && isAirplaneModeOn() && isAirplaneToggleable()); sendEnableMessage(enable, true, Binder.getCallingUid()); } return true; } private void enforceChangePermission() { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE, "WifiService"); }
enforceCallingOrSelfPermission(..,..)函數就是檢查是否具備權限,若沒有則拋出異常。Binder.clearCallingIdentity()和Binder.restoreCallingIdentity()這兩個方法,它的主要做用是暫時得到系統權限,acquire函數就是申請一把鎖,之後釋放。後面的sendEnableMessage函數 異步
private void sendEnableMessage(boolean enable, boolean persist, int uid) { Message msg = Message.obtain(mWifiHandler, (enable ? MESSAGE_ENABLE_WIFI : MESSAGE_DISABLE_WIFI), (persist ? 1 : 0), uid); msg.sendToTarget(); }這個學android的人應該都知道是什麼吧,看看handler
/** * Handler that allows posting to the WifiThread. */ private class WifiHandler extends Handler { public WifiHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { switch (msg.what) { case MESSAGE_ENABLE_WIFI: setWifiEnabledBlocking(true, msg.arg1 == 1, msg.arg2); if (mWifiWatchdogService == null) { mWifiWatchdogService = new WifiWatchdogService(mContext, mWifiStateTracker); } sWakeLock.release(); break; } } }
這裏的msg.arg2就是uid,看下里面的setWifiEnabledBlocking函數,此代碼段爲代碼段一! socket
/** * Enables/disables Wi-Fi synchronously. * @param enable {@code true} to turn Wi-Fi on, {@code false} to turn it off. * @param persist {@code true} if the setting should be persisted. * @param uid The UID of the process making the request. * @return {@code true} if the operation succeeds (or if the existing state * is the same as the requested state) */ private boolean setWifiEnabledBlocking(boolean enable, boolean persist, int uid) { final int eventualWifiState = enable ? WIFI_STATE_ENABLED : WIFI_STATE_DISABLED; final int wifiState = mWifiStateTracker.getWifiState(); if (wifiState == eventualWifiState) { return true; } if (enable && isAirplaneModeOn() && !mAirplaneModeOverwridden) { return false; } /** * Multiple calls to unregisterReceiver() cause exception and a system crash. * This can happen if a supplicant is lost (or firmware crash occurs) and user indicates * disable wifi at the same time. * Avoid doing a disable when the current Wifi state is UNKNOWN * TODO: Handle driver load fail and supplicant lost as seperate states */ if ((wifiState == WIFI_STATE_UNKNOWN) && !enable) { return false; } /** * Fail Wifi if AP is enabled * TODO: Deprecate WIFI_STATE_UNKNOWN and rename it * WIFI_STATE_FAILED */ if ((mWifiApState == WIFI_AP_STATE_ENABLED) && enable) { setWifiEnabledState(WIFI_STATE_UNKNOWN, uid); return false; } setWifiEnabledState(enable ? WIFI_STATE_ENABLING : WIFI_STATE_DISABLING, uid); if (enable) { if (!mWifiStateTracker.loadDriver()) { Slog.e(TAG, "Failed to load Wi-Fi driver."); setWifiEnabledState(WIFI_STATE_UNKNOWN, uid); return false; } if (!mWifiStateTracker.startSupplicant()) { mWifiStateTracker.unloadDriver(); Slog.e(TAG, "Failed to start supplicant daemon."); setWifiEnabledState(WIFI_STATE_UNKNOWN, uid); return false; } registerForBroadcasts(); mWifiStateTracker.startEventLoop(); } }關鍵的就是從WifiStateTracker的loadDriver和startSupplicant開始(frameworks/base/wifi/java/android/net/wifi)
public synchronized boolean loadDriver() { return WifiNative.loadDriver(); }
public synchronized boolean startSupplicant() { return WifiNative.startSupplicant(); }
這調用了WifiNative的loadDriver與startSupplicant函數,注意,全部的WifiNative中的調用都須要發生在WifiStateTracker類中,除了waitForEvent() ide
public class WifiNative { public native static boolean loadDriver(); public native static boolean startSupplicant(); }
static jboolean android_net_wifi_loadDriver(JNIEnv* env, jobject clazz) { return (jboolean)(::wifi_load_driver() == 0); } static jboolean android_net_wifi_startSupplicant(JNIEnv* env, jobject clazz) { return (jboolean)(::wifi_start_supplicant() == 0); }而這兩個系統級的函數實現於wifi.c(hardware/libhardware_legacy)
int wifi_load_driver() { char driver_status[PROPERTY_VALUE_MAX]; int count = 100; /* wait at most 20 seconds for completion */ if (check_driver_loaded()) { return 0; } if (insmod(DRIVER_MODULE_PATH, DRIVER_MODULE_ARG) < 0) return -1; if (strcmp(FIRMWARE_LOADER,"") == 0) { usleep(WIFI_DRIVER_LOADER_DELAY); property_set(DRIVER_PROP_NAME, "ok"); } else { property_set("ctl.start", FIRMWARE_LOADER); } sched_yield(); while (count-- > 0) { if (property_get(DRIVER_PROP_NAME, driver_status, NULL)) { if (strcmp(driver_status, "ok") == 0) return 0; else if (strcmp(DRIVER_PROP_NAME, "failed") == 0) { wifi_unload_driver(); return -1; } } usleep(200000); } property_set(DRIVER_PROP_NAME, "timeout"); wifi_unload_driver(); return -1; } int wifi_unload_driver() { int count = 20; /* wait at most 10 seconds for completion */ if (rmmod(DRIVER_MODULE_NAME) == 0) { while (count-- > 0) { if (!check_driver_loaded()) break; usleep(500000); } if (count) { return 0; } return -1; } else return -1; }
這些都是驅動相關的信息,下面的是startSupplicant函數的實現 函數
int wifi_start_supplicant() { char supp_status[PROPERTY_VALUE_MAX] = {'\0'}; int count = 200; /* wait at most 20 seconds for completion */ #ifdef HAVE_LIBC_SYSTEM_PROPERTIES const prop_info *pi; unsigned serial = 0; #endif /* Check whether already running */ if (property_get(SUPP_PROP_NAME, supp_status, NULL) && strcmp(supp_status, "running") == 0) { return 0; } /* Before starting the daemon, make sure its config file exists */ if (ensure_config_file_exists() < 0) { LOGE("Wi-Fi will not be enabled"); return -1; } /* Clear out any stale socket files that might be left over. */ wpa_ctrl_cleanup(); #ifdef HAVE_LIBC_SYSTEM_PROPERTIES /* * Get a reference to the status property, so we can distinguish * the case where it goes stopped => running => stopped (i.e., * it start up, but fails right away) from the case in which * it starts in the stopped state and never manages to start * running at all. */ pi = __system_property_find(SUPP_PROP_NAME); if (pi != NULL) { serial = pi->serial; } #endif property_set("ctl.start", SUPPLICANT_NAME); sched_yield(); while (count-- > 0) { #ifdef HAVE_LIBC_SYSTEM_PROPERTIES if (pi == NULL) { pi = __system_property_find(SUPP_PROP_NAME); } if (pi != NULL) { __system_property_read(pi, NULL, supp_status); if (strcmp(supp_status, "running") == 0) { return 0; } else if (pi->serial != serial && strcmp(supp_status, "stopped") == 0) { return -1; } } #else if (property_get(SUPP_PROP_NAME, supp_status, NULL)) { if (strcmp(supp_status, "running") == 0) return 0; } #endif usleep(100000); } return -1; }
這段代碼是屬於啓動supplicant服務。 oop
如今繼續回到代碼段一,往下走是setWifiEnabledState函數,此處爲代碼段二!
private void setWifiEnabledState(int wifiState, int uid) { final int previousWifiState = mWifiStateTracker.getWifiState(); long ident = Binder.clearCallingIdentity(); try { if (wifiState == WIFI_STATE_ENABLED) { mBatteryStats.noteWifiOn(); } else if (wifiState == WIFI_STATE_DISABLED) { mBatteryStats.noteWifiOff(); } } catch (RemoteException e) { } finally { Binder.restoreCallingIdentity(ident); } // Update state mWifiStateTracker.setWifiState(wifiState); // Broadcast final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState); intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState); mContext.sendStickyBroadcast(intent); }try那一塊的功能就是在得到系統權限後根據wifi狀態更改,一樣是經過stub,BatteryStatsService.java裏面實現(frameworks/base/services/java/com/android/server/am)
public final class BatteryStatsService extends IBatteryStats.Stub { final BatteryStatsImpl mStats; public void noteWifiOn() { enforceCallingPermission(); synchronized (mStats) { mStats.noteWifiOnLocked(); } } }
查找BatteryStateImpl.java(freameworks/base/core/java/com/android/internal/os)
public void noteWifiOnLocked() { if (!mWifiOn) { mHistoryCur.states |= HistoryItem.STATE_WIFI_ON_FLAG; if (DEBUG_HISTORY) Slog.v(TAG, "WIFI on to: " + Integer.toHexString(mHistoryCur.states)); addHistoryRecordLocked(SystemClock.elapsedRealtime()); mWifiOn = true; mWifiOnTimer.startRunningLocked(this); } }其中的mWifiOnTimer是個StopwatchTimer類型的對象,mWifiOn只是一個boolean類型。再看看代碼段二
public void setWifiState(int wifiState) { mWifiState.set(wifiState); }而mWifistated的聲明爲
/** * One of {@link WifiManager#WIFI_STATE_DISABLED}, * {@link WifiManager#WIFI_STATE_DISABLING}, * {@link WifiManager#WIFI_STATE_ENABLED}, * {@link WifiManager#WIFI_STATE_ENABLING}, * {@link WifiManager#WIFI_STATE_UNKNOWN} * * getWifiState() is not synchronized to make sure it's always fast, * even when the instance lock is held on other slow operations. * Use a atomic variable for state. */ private final AtomicInteger mWifiState = new AtomicInteger(WIFI_STATE_UNKNOWN);
AtomicInteger,一個提供原子操做的Integer的類。在Java語言中,++i和i++操做並非線程安全的,在使用的時候,不可避免的會用到synchronized關鍵字。而AtomicInteger則經過一種線程安全的加減操做接口。再接着看代碼段二,就是講wifi事件廣播出去,通知監聽此事件的事務。然而在wifisettings.java(packages/apps/settings/src/com/android/settings/wifi)裏面會監聽到此事件。
private void handleEvent(Intent intent) { String action = intent.getAction(); if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) { updateWifiState(intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN)); } else if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(action)) { updateAccessPoints(); } }監聽到進行updateWifiState處理, 此處爲代碼段三!
private void updateWifiState(int state) { if (state == WifiManager.WIFI_STATE_ENABLED) { mScanner.resume(); updateAccessPoints(); } else { mScanner.pause(); mAccessPoints.removeAll(); } }因爲先前傳入的就是WIFI_STATE_ENABLED,因此進行resume與updateAccessPoints函數處理。先看下Scanner吧
private class Scanner extends Handler { private int mRetry = 0; void resume() { if (!hasMessages(0)) { sendEmptyMessage(0); } } void pause() { mRetry = 0; mAccessPoints.setProgress(false); removeMessages(0); } @Override public void handleMessage(Message message) { if (mWifiManager.startScanActive()) { mRetry = 0; } else if (++mRetry >= 3) { mRetry = 0; Toast.makeText(WifiSettings.this, R.string.wifi_fail_to_scan, Toast.LENGTH_LONG).show(); return; } mAccessPoints.setProgress(mRetry != 0); sendEmptyMessageDelayed(0, 6000); }startScanActive他會調用wifiManager.java裏面的startScanActive函數
public boolean startScanActive() { try { mService.startScan(true); return true; } catch (RemoteException e) { return false; } }接着會調用wifiService.java裏面的startScan函數
public void startScan(boolean forceActive) { enforceChangePermission(); if (mWifiHandler == null) return; Message.obtain(mWifiHandler, MESSAGE_START_SCAN, forceActive ? 1 : 0, 0).sendToTarget(); }
發送消息到wifiHandler,那麼看下對應的響應,此處爲代碼段四!
case MESSAGE_START_SCAN: boolean forceActive = (msg.arg1 == 1); switch (mWifiStateTracker.getSupplicantState()) { case DISCONNECTED: case INACTIVE: case SCANNING: case DORMANT: break; default: mWifiStateTracker.setScanResultHandling( WifiStateTracker.SUPPL_SCAN_HANDLING_LIST_ONLY); break; } mWifiStateTracker.scan(forceActive); break;首選根據supplicant的狀態來執行不一樣的方法
public SupplicantState getSupplicantState() { return mWifiInfo.getSupplicantState(); }從wifiInfo中獲取supplicantState
public SupplicantState getSupplicantState() { return mSupplicantState; }
這個返回的是supplicantState與AP協商後的詳細狀態。(Return the detailed state of the supplicant's negotiation with an access point)。接着看代碼段四,下面遇到兩個函數
public synchronized boolean scan(boolean forceActive) { if (mWifiState.get() != WIFI_STATE_ENABLED || isDriverStopped()) { return false; } return WifiNative.scanCommand(forceActive); } /** * Specifies whether the supplicant or driver * take care of initiating scan and doing AP selection * * @param mode * SUPPL_SCAN_HANDLING_NORMAL * SUPPL_SCAN_HANDLING_LIST_ONLY * @return {@code true} if the operation succeeds, {@code false} otherwise */ public synchronized boolean setScanResultHandling(int mode) { if (mWifiState.get() != WIFI_STATE_ENABLED) { return false; } return WifiNative.setScanResultHandlingCommand(mode); }這個又遇到wifiNative,因而又要運用JNI去調用底層代碼,在android_net_wifi_WIFI.cpp裏面
static jboolean android_net_wifi_scanCommand(JNIEnv* env, jobject clazz, jboolean forceActive) { jboolean result; // Ignore any error from setting the scan mode. // The scan will still work. if (forceActive && !sScanModeActive) doSetScanMode(true); result = doBooleanCommand("SCAN", "OK"); if (forceActive && !sScanModeActive) doSetScanMode(sScanModeActive); return result; }這裏面的doSetScanMode其實也是調用的doBooleanCommand
static jboolean doSetScanMode(jboolean setActive) { return doBooleanCommand((setActive ? "DRIVER SCAN-ACTIVE" : "DRIVER SCAN-PASSIVE"), "OK"); }那麼doBooleanCommand是什麼呢
static jboolean doBooleanCommand(const char *cmd, const char *expect) { char reply[256]; if (doCommand(cmd, reply, sizeof(reply)) != 0) { return (jboolean)JNI_FALSE; } else { return (jboolean)(strcmp(reply, expect) == 0); } } static int doCommand(const char *cmd, char *replybuf, int replybuflen) { size_t reply_len = replybuflen - 1; if (::wifi_command(cmd, replybuf, &reply_len) != 0) return -1; else { // Strip off trailing newline if (reply_len > 0 && replybuf[reply_len-1] == '\n') replybuf[reply_len-1] = '\0'; else replybuf[reply_len] = '\0'; return 0; } }而wifi_command在wifi.c中實現
int wifi_command(const char *command, char *reply, size_t *reply_len) { return wifi_send_command(ctrl_conn, command, reply, reply_len); }
接下來看看wifi_send_command函數,在wifi.c裏面
int wifi_send_command(struct wpa_ctrl *ctrl, const char *cmd, char *reply, size_t *reply_len) { int ret; if (ctrl_conn == NULL) { LOGV("Not connected to wpa_supplicant - \"%s\" command dropped.\n", cmd); return -1; } ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), reply, reply_len, NULL); if (ret == -2) { LOGD("'%s' command timed out.\n", cmd); return -2; } else if (ret < 0 || strncmp(reply, "FAIL", 4) == 0) { return -1; } if (strncmp(cmd, "PING", 4) == 0) { reply[*reply_len] = '\0'; } return 0; }這裏面有個struct,很重要
struct wpa_ctrl { #ifdef CONFIG_CTRL_IFACE_UDP int s; struct sockaddr_in local; struct sockaddr_in dest; char *cookie; #endif /* CONFIG_CTRL_IFACE_UDP */ #ifdef CONFIG_CTRL_IFACE_UNIX int s; struct sockaddr_un local; struct sockaddr_un dest; #endif /* CONFIG_CTRL_IFACE_UNIX */ #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE HANDLE pipe; #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ };這個類中聲明瞭兩個Socket套接口,一個是本地一個是要鏈接的套接 口,wpa_ctrl與wpa_supplicant的通訊就須要socket來幫忙了,而wpa_supplicant就是經過調用 wpa_ctrl.h中定義的函數和wpa_supplicant進行通信的,wpa_ctrl類(實際上是其中的兩個socket)就是他們之間的橋樑。
wpa_ctrl_request,這個函數存放在wpa_ctrl.c(external/wpa_supplicant)
int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, char *reply, size_t *reply_len, void (*msg_cb)(char *msg, size_t len)) { struct timeval tv; int res; fd_set rfds; const char *_cmd; char *cmd_buf = NULL; size_t _cmd_len; #ifdef CONFIG_CTRL_IFACE_UDP if (ctrl->cookie) { char *pos; _cmd_len = strlen(ctrl->cookie) + 1 + cmd_len; cmd_buf = os_malloc(_cmd_len ); if (cmd_buf == NULL) return -1; _cmd = cmd_buf; pos = cmd_buf; strcpy(pos, ctrl->cookie); pos += strlen(ctrl->cookie); *pos++ = ' '; memcpy(pos, cmd, cmd_len); } else #endif /* CONFIG_CTRL_IFACE_UDP */ { _cmd = cmd; _cmd_len = cmd_len; } if (send(ctrl->s, _cmd, _cmd_len, 0) < 0) { os_free(cmd_buf); return -1; } os_free(cmd_buf); for (;;) { #ifdef ANDROID tv.tv_sec = 10; #else tv.tv_sec = 2; #endif tv.tv_usec = 0; FD_ZERO(&rfds); FD_SET(ctrl->s, &rfds); res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv); if (FD_ISSET(ctrl->s, &rfds)) { res = recv(ctrl->s, reply, *reply_len, 0); if (res < 0) return res; if (res > 0 && reply[0] == '<') { /* This is an unsolicited message from * wpa_supplicant, not the reply to the * request. Use msg_cb to report this to the * caller. */ if (msg_cb) { /* Make sure the message is nul * terminated. */ if ((size_t) res == *reply_len) res = (*reply_len) - 1; reply[res] = '\0'; msg_cb(reply, res); } continue; } *reply_len = res; break; } else { return -2; } } return 0; }This function is used to send commands to wpa_supplicant/hostapd. Received response will be written to reply and reply_len is set to the actual length of the reply. This function will block for up to two seconds while waiting for the reply. If unsolicited messages are received, the blocking time may be longer.
如今回到代碼段三,後面有個update函數
private void updateAccessPoints() { List<AccessPoint> accessPoints = new ArrayList<AccessPoint>(); List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks(); if (configs != null) { mLastPriority = 0; for (WifiConfiguration config : configs) { if (config.priority > mLastPriority) { mLastPriority = config.priority; } // Shift the status to make enableNetworks() more efficient. if (config.status == Status.CURRENT) { config.status = Status.ENABLED; } else if (mResetNetworks && config.status == Status.DISABLED) { config.status = Status.CURRENT; } AccessPoint accessPoint = new AccessPoint(this, config); accessPoint.update(mLastInfo, mLastState); accessPoints.add(accessPoint); } } List<ScanResult> results = mWifiManager.getScanResults(); if (results != null) { for (ScanResult result : results) { // Ignore hidden and ad-hoc networks. if (result.SSID == null || result.SSID.length() == 0 || result.capabilities.contains("[IBSS]")) { continue; } boolean found = false; for (AccessPoint accessPoint : accessPoints) { if (accessPoint.update(result)) { found = true; } } if (!found) { accessPoints.add(new AccessPoint(this, result)); } } } mAccessPoints.removeAll(); for (AccessPoint accessPoint : accessPoints) { mAccessPoints.addPreference(accessPoint); } }這個就是更新AP並經過GUI的形式列出來。