android中wifi原理及流程分析

wifi相關(guān)的文件位置:

WIFI Settings應(yīng)用程序位于

   packages/apps/Settings/src/com/android/settings/wifi/

JAVA部分:

    frameworks/base/services/java/com/android/server/

    frameworks/base/wifi/java/android/net/wifi/

JNI部分:

   frameworks/base/core/jni/android_net_wifi_Wifi.cpp

wifi管理庫(kù)。

    hardware/libhardware_legary/wifi/

wifi用戶空間的程序和庫(kù):

    external/wpa_supplicant/

   生成庫(kù)libwpaclient.so和守護(hù)進(jìn)程wpa_supplicant占调。

調(diào)用流程:

wifi模塊的初始化:

(frameworks/base/services/java/com/android/server/SystemServer.Java)

在 SystemServer 啟動(dòng)的時(shí)候,會(huì)生成一個(gè)ConnectivityService 的實(shí)例,

classServerThread extends Thread {

稼稿。卸伞。。贝乎。关斜。。秘通。为严。。肺稀。梗脾。。盹靴。炸茧。。稿静。梭冠。。改备。控漠。。悬钳。盐捷。。默勾。碉渡。。母剥。滞诺。。环疼。习霹。。炫隶。淋叶。。伪阶。煞檩。。望门。形娇。。
try {

            Slog.i(TAG,"Connectivity Service");

            connectivity= **ConnectivityService.getInstance(context);**

           ServiceManager.addService(Context.CONNECTIVITY_SERVICE,connectivity);

        } catch(Throwable e) {

            Slog.e(TAG,"Failure starting Connectivity Service", e);

        }

筹误。桐早。。厨剪。哄酝。。祷膳。陶衅。。直晨。搀军。膨俐。。罩句。焚刺。。门烂。乳愉。。屯远。蔓姚。。慨丐。坡脐。。咖气。挨措。。崩溪。浅役。。伶唯。觉既。。乳幸。瞪讼。。粹断。符欠。。瓶埋。希柿。。养筒。曾撤。。晕粪。挤悉。。巫湘。装悲。昏鹃。。衅斩。盆顾。。畏梆。。奈懒。奠涌。。磷杏。溜畅。。

}

其中 极祸,ConnectivityService.getInstance(context); 對(duì)應(yīng)于(frameworks/base/services/java/com/android/server/ ConnectivityService.JavaConnectivityService.Java慈格。

下面看下ConnectivityService.Java中的

public static ConnectivityServicegetInstance(Context context) {

   return** ConnectivityThread.getServiceInstance**(context);

}函數(shù), 繼續(xù)往下看:

       public static ConnectivityService getServiceInstance(Context context) {

           ConnectivityThread thread = **newConnectivityThread**(context);

            thread.start();

           synchronized (thread) {

               while (sServiceInstance == null) {

                    try {

                        // Wait until sServiceInstance has beeninitialized.

                        thread.wait();

                    } catch (InterruptedExceptionignore) {

                        Slog.e(TAG,

                            "UnexpectedInterruptedException while waiting"+

                            " forConnectivityService thread");

                    }

               }

           }

            return sServiceInstance;

        }

    }

繼續(xù)往下跟:

private static class **ConnectivityThread **extends Thread {

       private Context mContext;

       private ConnectivityThread(Context context) {

           super("ConnectivityThread");

           mContext = context;

        }

       @Override

   **     public void run() {**

           Looper.prepare();

           synchronized (this) {

               sServiceInstance = **newConnectivityService**(mContext);

               notifyAll();

           }

            Looper.loop();

        }

       public static ConnectivityService getServiceInstance(Context context) {

           ConnectivityThread thread = new ConnectivityThread(context);

           thread.start();

           synchronized (thread) {

                while (sServiceInstance == null) {

                    try {

                        // Wait untilsServiceInstance has been initialized.

                        thread.wait();

                    } catch(InterruptedException ignore) {

                        Slog.e(TAG,

                            "UnexpectedInterruptedException while waiting"+

                            " forConnectivityService thread");

                    }

               }

           }

           return sServiceInstance;

        }

    }

繼續(xù)**newConnectivityService**(mContext)

private ConnectivityService(Context context) {

遥金。浴捆。。稿械。选泻。。美莫。页眯。。厢呵。窝撵。。襟铭。碌奉。。蝌矛。道批。。入撒。隆豹。。茅逮。璃赡。判哥。。碉考。塌计。。侯谁。锌仅。

    for(int netType : mPriorityList) {

           switch (mNetAttributes[netType].mRadio) {

           case ConnectivityManager.TYPE_WIFI:

               Slog.v(TAG, "Starting Wifi Service.");

              ** WifiStateTracker wst = newWifiStateTracker(context, mHandler);**

               WifiService wifiService = **newWifiService(context, wst);**

               **ServiceManager.addService(Context.WIFI_SERVICE,wifiService);**

               **wifiService.startWifi();//啟動(dòng)wifiservice**

               mNetTrackers[ConnectivityManager.TYPE_WIFI] = wst;

               **wst.startMonitoring();//啟動(dòng)Monitoring**

               break;   。墙贱。热芹。。惨撇。

          }//endfor

伊脓。。魁衙。报腔。。剖淀。纯蛾。。祷蝌。茅撞。。巨朦。米丘。。糊啡。拄查。。棚蓄。堕扶。。梭依。稍算。。役拴。糊探。。

}

到這里模塊初始化的工作完成,具體流程圖如下:

image.png

WifiStateTracker 會(huì)創(chuàng)建 WifiMonitor 接收來自底層的事件, WifiService 和 WifiMonitor 是整個(gè)模塊的核心科平。WifiService 負(fù)責(zé)啟動(dòng)關(guān)閉 wpa_supplicant褥紫、啟動(dòng)關(guān)閉 WifiMonitor 監(jiān)視線程和把命令下發(fā)給 wpa_supplicant,而 WifiMonitor 則負(fù)責(zé)從 wpa_supplicant 接收事件通知。

也就是說WifiService負(fù)責(zé)wifi整個(gè)流程的控制瞪慧,而WifiMonitor負(fù)責(zé)監(jiān)視底層的事件髓考。

此時(shí)WifiService starting up withWi-Fi disabled,

Wifi模塊的啟動(dòng)(Enable):

packages/apps/Settings/src/com/android/settings/wifi/ WirelessSettings.java

WirelessSettings 在初始化的時(shí)候配置了由WifiEnabler 來處理Wifi 按鈕弃酌,

    protected void onCreate(BundlesavedInstanceState) {

        super.onCreate(savedInstanceState);

        mWifiManager = (WifiManager)getSystemService(Context.WIFI_SERVICE);

        if (getIntent().getBooleanExtra("only_access_points",false)) {

           addPreferencesFromResource(R.xml.wifi_access_points);

        } else {

           addPreferencesFromResource(R.xml.wifi_settings);

            **mWifiEnabler = new WifiEnabler(this,**

**                    (CheckBoxPreference)findPreference("enable_wifi"));**

            mNotifyOpenNetworks =

                    (CheckBoxPreference)findPreference("notify_open_networks");

           mNotifyOpenNetworks.setChecked(Secure.getInt(getContentResolver(),

                    Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,0) == 1);

        }

        mAccessPoints = (ProgressCategory)findPreference("access_points");

       mAccessPoints.setOrderingAsAdded(false);

        mAddNetwork =findPreference("add_network");

        registerForContextMenu(getListView());

    }

然后調(diào)用:**(**packages/apps/Settings/src/com/android/settings/wifi/ **WifiEnabler.java)**

publicclass WifiEnabler implements Preference.OnPreferenceChangeListener {

氨菇。。矢腻。门驾。。多柑。。楣责。竣灌。。秆麸。初嘹。。沮趣。屯烦。。房铭。驻龟。。缸匪。翁狐。。

  public boolean onPreferenceChange(Preferencepreference, Object value) {

凌蔬。露懒。。砂心。懈词。。辩诞。坎弯。。。荞怒。洒琢。。褐桌。衰抑。。荧嵌。呛踊。。啦撮。谭网。。赃春。愉择。。织中。锥涕。

        if (mWifiManager.**setWifiEnabled(enable)**){

            mCheckBox.setEnabled(false);

        } else {

           mCheckBox.setSummary(R.string.wifi_error);

        }

。狭吼。层坠。。刁笙。破花。。疲吸。座每。。磅氨。尺栖。。烦租。延赌。。叉橱。挫以。。窃祝。掐松。。

        }

。大磺。抡句。。杠愧。待榔。。流济。锐锣。。绳瘟。雕憔。。糖声。斤彼。。蘸泻。畅卓。。蟋恬。。

}

調(diào)用:

**(**packages/apps/Settings/src/com/android/settings/wifi/ **WifiManager.java)**

   public boolean setWifiEnabled(booleanenabled) {

        try {

            returnmService.**setWifiEnabled**(enabled);

        } catch(RemoteException e) {

            returnfalse;

        }

    }
  當(dāng)用戶按下 Wifi 按鈕后,  Android 會(huì)調(diào)用 WifiEnabler 的onPreferenceChange,  再由 WifiEnabler調(diào)用 WifiManager 的 **setWifiEnabled** 接口函數(shù),通過 AIDL,實(shí)際調(diào)用的是 WifiService 的**setWifiEnabled** 函數(shù),WifiService 接著向自身發(fā)送一條 MESSAGE_ENABLE_WIFI 消息,在處理該消息的代碼中做真正的使能工作:首先裝載 WIFI 內(nèi)核模塊(該模塊的位置硬編碼為"/system/lib/modules/wlan.ko" ), 然 后 啟 動(dòng) wpa_supplicant ( 配 置 文 件 硬 編 碼 為"/data/misc/wifi/wpa_supplicant.conf")再通過 WifiStateTracker 來啟動(dòng) WifiMonitor 中的監(jiān)視線程趁冈。

WifiService(WifiService.java) 收到MESSAGE_ENABLE_WIFI 消息后的操作如下:

AIDL:

Android Interface Definition Language,即Android接口描述語言歼争。Android系統(tǒng)中的進(jìn)程之間不能共享內(nèi)存,因此渗勘,需要提供一些機(jī)制在不同進(jìn)程之間進(jìn)行數(shù)據(jù)通信沐绒。

為了使其他的應(yīng)用程序也可以訪問本應(yīng)用程序提供的服務(wù),Android系統(tǒng)采用了遠(yuǎn)程過程調(diào)用(Remote Procedure Call旺坠,RPC)方式來實(shí)現(xiàn)乔遮。與很多其他的基于RPC的解決方案一樣,Android使用一種接口定義語言(InterfaceDefinition Language取刃,IDL)來公開服務(wù)的接口蹋肮。因此,可以將這種可以跨進(jìn)程訪問的服務(wù)稱為AIDL(Android Interface Definition Language)服務(wù)璧疗。

接下來繼續(xù)道wifiService.Java

(frameworks/base/services/java/com/android/server/ **wifiService.Java**)

    public boolean **setWifiEnabled(**boolean enable) {

        enforceChangePermission();

        if (mWifiHandler == null) return false;

        synchronized (mWifiHandler) {

            // caller may not have WAKE_LOCKpermission - it's not required here

            long ident =Binder.clearCallingIdentity();

            sWakeLock.acquire();

           Binder.restoreCallingIdentity(ident);

            mLastEnableUid =Binder.getCallingUid();

            // set a flag if the user isenabling Wifi while in airplane mode

            mAirplaneModeOverwridden = (enable&& isAirplaneModeOn() && isAirplaneToggleable());

            **sendEnableMessage(enable, true,Binder.getCallingUid());**  //  **here send a mesage to himself**

        }

        return true;

    }

繼續(xù)往下:

    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();**

    }

WifiHandler會(huì)收到消息:

private class **WifiHandler**extends Handler {

坯辩。。崩侠。漆魔。。。改抡。矢炼。。阿纤。句灌。。阵赠。涯塔。。清蚀。匕荸。噩翠。惊豺。馍惹。赔蒲。驰坊。循衰。意狠。乡恕。嘶卧。尔觉。。芥吟。侦铜。。钟鸵。钉稍。。棺耍。贡未。。蒙袍。俊卤。。左敌。瘾蛋。。矫限。哺哼。佩抹。

public voidhandleMessage(Message msg) {

            switch (msg.what) {

                case MESSAGE_ENABLE_WIFI:

                    **setWifiEnabledBlocking(true, msg.arg1 == 1,msg.arg2);**

                    if (mWifiWatchdogService ==null) {

                        mWifiWatchdogService = newWifiWatchdogService(mContext, mWifiStateTracker);

                    }

                    sWakeLock.release();

                    break;

。取董。棍苹。。茵汰。枢里。。蹂午。栏豺。。豆胸。奥洼。。晚胡。灵奖。。估盘。瓷患。。遣妥。擅编。。箫踩。沙咏。。班套。。故河。吱韭。。

                  }

鱼的。理盆。。凑阶。猿规。。宙橱。姨俩。蘸拔。。环葵。调窍。。张遭。邓萨。。菊卷。缔恳。。洁闰。歉甚。。渴庆。铃芦。。襟雷。刃滓。。耸弄。咧虎。。计呈。砰诵。。捌显。

}

privateboolean **setWifiEnabledBlocking**(booleanenable, boolean persist, int uid) {

茁彭。。扶歪。理肺。。善镰。妹萨。。炫欺。乎完。。品洛。

**  setWifiEnabledState(enable ?WIFI_STATE_ENABLING : WIFI_STATE_DISABLING, uid);**

** if (enable) {**

            if (!mWifiStateTracker.**loadDriver()**){

                Slog.e(TAG, "Failed toload Wi-Fi driver.");

               setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);

                return false;

            }

            if (!mWifiStateTracker.**startSupplicant()**){

               mWifiStateTracker.unloadDriver();

                Slog.e(TAG, "Failed tostart supplicant daemon.");

               setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);

                return false;

            }

            registerForBroadcasts();

            mWifiStateTracker.**startEventLoop()**;

**        } else {**

           mContext.unregisterReceiver(mReceiver);

           // Remove notification (it willno-op if it isn't visible)

            mWifiStateTracker.**setNotificationVisible**(false,0, false, 0);

            booleanfailedToStopSupplicantOrUnloadDriver = false;

            if (!mWifiStateTracker.**stopSupplicant()**){

                Slog.e(TAG, "Failed tostop supplicant daemon.");

                setWifiEnabledState(WIFI_STATE_UNKNOWN,uid);

               failedToStopSupplicantOrUnloadDriver = true;

            }

            /**

             * Reset connections and disableinterface

             * before we unload the driver

             */

            mWifiStateTracker.**resetConnections(true)**;

            if (!mWifiStateTracker.**unloadDriver()**){

                Slog.e(TAG, "Failed tounload Wi-Fi driver.");

                if(!failedToStopSupplicantOrUnloadDriver) {

                    setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);

                   failedToStopSupplicantOrUnloadDriver = true;

                }

            }

            if(failedToStopSupplicantOrUnloadDriver) {

                return false;

**            }**

        }

树姨。摩桶。。娃弓。典格。。台丛。耍缴。。挽霉。防嗡。。侠坎。蚁趁。。实胸。他嫡。。庐完。钢属。。门躯。

}

具體流程如下流程圖所示:

image.png
image.png

掃描查找熱點(diǎn)(AP)

上一節(jié)中講到Wifi模塊開啟后會(huì)對(duì)外發(fā)送WIFI_STATE_CHANGED_ACTION淆党。WifiLayer中注冊(cè)了Action的Receiver。
當(dāng)WifiLayer收到此Action后開始scan的流程讶凉,具體如下:

image.png

當(dāng)wpa_supplicant 處理完SCAN 命令后染乌,它會(huì)向控制通道發(fā)送事件通知掃描完成,從wifi_wait_for_event函數(shù)會(huì)接收到該事件懂讯,由此WifiMonitor 中的MonitorThread會(huì)被執(zhí)行來出來這個(gè)事件:

image.png

配置 AP 參數(shù)
當(dāng)用戶在WifiSettings 界面上選擇了一個(gè)AP 后荷憋,會(huì)顯示配置AP 參數(shù)的一個(gè)對(duì)話框:

image.png

Wifi連接

具體流程參見以下流程圖:

image.png

IP地址的配置
流程如圖:

image.png

到此結(jié)束。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末褐望,一起剝皮案震驚了整個(gè)濱河市台谊,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌譬挚,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,590評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件酪呻,死亡現(xiàn)場(chǎng)離奇詭異减宣,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)玩荠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門漆腌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來贼邓,“玉大人,你說我怎么就攤上這事闷尿∷芫叮” “怎么了?”我有些...
    開封第一講書人閱讀 169,301評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵填具,是天一觀的道長(zhǎng)统舀。 經(jīng)常有香客問我,道長(zhǎng)劳景,這世上最難降的妖魔是什么誉简? 我笑而不...
    開封第一講書人閱讀 60,078評(píng)論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮盟广,結(jié)果婚禮上闷串,老公的妹妹穿的比我還像新娘。我一直安慰自己筋量,他們只是感情好烹吵,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,082評(píng)論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著桨武,像睡著了一般肋拔。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上玻募,一...
    開封第一講書人閱讀 52,682評(píng)論 1 312
  • 那天只损,我揣著相機(jī)與錄音,去河邊找鬼七咧。 笑死跃惫,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的艾栋。 我是一名探鬼主播爆存,決...
    沈念sama閱讀 41,155評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼蝗砾!你這毒婦竟也來了先较?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,098評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤悼粮,失蹤者是張志新(化名)和其女友劉穎闲勺,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體扣猫,經(jīng)...
    沈念sama閱讀 46,638評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡菜循,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,701評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了申尤。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片癌幕。...
    茶點(diǎn)故事閱讀 40,852評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡衙耕,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出勺远,到底是詐尸還是另有隱情橙喘,我是刑警寧澤,帶...
    沈念sama閱讀 36,520評(píng)論 5 351
  • 正文 年R本政府宣布胶逢,位于F島的核電站厅瞎,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏宪塔。R本人自食惡果不足惜磁奖,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,181評(píng)論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望某筐。 院中可真熱鬧比搭,春花似錦、人聲如沸南誊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,674評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽抄囚。三九已至霉赡,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間幔托,已是汗流浹背穴亏。 一陣腳步聲響...
    開封第一講書人閱讀 33,788評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留重挑,地道東北人嗓化。 一個(gè)月前我還...
    沈念sama閱讀 49,279評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像谬哀,于是被迫代替她去往敵國(guó)和親刺覆。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,851評(píng)論 2 361