<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                Android 4.2中,Captive Portal Check功能集中在CaptivePortalTracker類中,而且它也是一個HSM。CaptivePortalTracker的創建位于ConnectivityService構造函數中。在那里,它的makeCaptivePortalTracker函數被調用。相關代碼如下所示: **CaptivePortalTracker.java::makeCaptivePortalTracker** ~~~ public static CaptivePortalTracker makeCaptivePortalTracker(Context context, IConnectivityManager cs) { CaptivePortalTracker captivePortal = new CaptivePortalTracker(context, cs); captivePortal.start();//啟動HSM return captivePortal; } ~~~ 馬上來看CaptivePortalTracker的構造函數 **1、CaptivePortalTracker構造函數分析** **CaptivePortalTracker.java::CaptivePortalTracker** ~~~ private CaptivePortalTracker(Context context, IConnectivityManager cs) { super(TAG); mContext = context;mConnService = cs; mTelephonyManager = (TelephonyManager) context.getSystemService( Context.TELEPHONY_SERVICE); //注冊一個廣播接收對象,用于處理CONNECTIVITY_ACTION消息 IntentFilter filter = new IntentFilter(); filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); mContext.registerReceiver(mReceiver, filter); //CAPTIVE_PORTAL_SERVER用于設置進行Captive Portal Check測試的服務器地址 mServer = Settings.Global.getString(mContext.getContentResolver(), Settings.Global.CAPTIVE_PORTAL_SERVER); //如果沒有指明服務器地址的,則采用DEFAULT_SERVER,其地址是“clients3.google.com” if (mServer == null) mServer = DEFAULT_SERVER; //是否開啟Captive Portal Check功能,默認是開始 mIsCaptivePortalCheckEnabled = Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.CAPTIVE_PORTAL_DETECTION_ENABLED, 1) == 1; addState(mDefaultState);//CaptivePortalTracker只有4個狀態 addState(mNoActiveNetworkState, mDefaultState); addState(mActiveNetworkState, mDefaultState); addState(mDelayedCaptiveCheckState, mActiveNetworkState); setInitialState(mNoActiveNetworkState); } ~~~ CaptivePortalTracker只監聽CONNECTIVITY_ACTION廣播,而WifiService相關模塊并不會發送這個廣播。那么,在前面介紹的流程中,哪一步會觸發CaptivePortalTracker進行工作呢?來看下節。 **2、CMD_CONNECTIVITY_CHANGE處理流程分析** 當Wifi網絡連接成功時,ConnectivityService的handleConnect將被觸發,該函數內部將發送一個CONNECTIVITY_ACTION消息。這個消息將被CaptivePortalTracker注冊的廣播接收對象處理。相關代碼如下所示: **CaptivePortalTracker.java::onReceive** ~~~ private final BroadcastReceiver mReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { NetworkInfo info = intent.getParcelableExtra( ConnectivityManager.EXTRA_NETWORK_INFO); //向狀態機發送CMD_CONNECTIVITY_CHANGE消息 sendMessage(obtainMessage(CMD_CONNECTIVITY_CHANGE, info)); } } }; ~~~ CaptivePortalTracker的NoActiveNetworkState將處理該消息。相關代碼如下所示: **CaptivePortalTracker.java::NoActiveNetworkState:processMessage** ~~~ public boolean processMessage(Message message) { InetAddress server; NetworkInfo info; switch (message.what) { case CMD_CONNECTIVITY_CHANGE: info = (NetworkInfo) message.obj; //無線網絡已經連接成功,并且手機當前使用的就是Wifi。isActiveNetwork將查詢 //ConnectivityService以獲取當前活躍的數據鏈接類型 if (info.isConnected() && isActiveNetwork(info)) { mNetworkInfo = info; transitionTo(mDelayedCaptiveCheckState);//轉移到DelayedCaptiveCheckState } ...... } return HANDLED; } ~~~ 來看DelayedCaptiveCheckState。 **3、CMD_DELAYED_CAPTIVE_CHECK處理流程分析** 代碼如下所示: **CaptivePortalTracker.java::DelayedCaptiveCheckState** ~~~ private class DelayedCaptiveCheckState extends State { public void enter() { //發送一個延遲消息,延遲時間為10秒 sendMessageDelayed(obtainMessage(CMD_DELAYED_CAPTIVE_CHECK, ++mDelayedCheckToken, 0), DELAYED_CHECK_INTERVAL_MS); } public boolean processMessage(Message message) { switch (message.what) { case CMD_DELAYED_CAPTIVE_CHECK: if (message.arg1 == mDelayedCheckToken) { InetAddress server = lookupHost(mServer);//獲取Server的ip地址 if (server != null) { //AP是否需要Captive Portal Check。如果是的話,setNotificiationVisible //將在狀態欄中添加一個提醒信息 if (isCaptivePortal(server)) setNotificationVisible(true); } transitionTo(mActiveNetworkState);//轉到ActiveNetworkState } break; default: return NOT_HANDLED; } return HANDLED; } } ~~~ 上述代碼中,isCaptivePortal用于判斷server是否需要Captive Portal Check。其代碼如下所示: **CaptivePortalTracker.java::isCaptivePortal** ~~~ private boolean isCaptivePortal(InetAddress server) { HttpURLConnection urlConnection = null; if (!mIsCaptivePortalCheckEnabled) return false; //mUrl實際訪問的地址是:http://clients3.google.com/generate_204 mUrl = "http://" + server.getHostAddress() + "/generate_204"; /* Captive Portal的測試非常簡單,就是向mUrl發送一個HTTP GET請求。如果無線網絡提供商沒有設置Portal Check,則HTTP GET請求將返回204。204表示請求處理成功,但沒有數據返回。如果無線網絡提供商設置了 Portal Check,則它一定會重定向到某個特定網頁。這樣,HTTP GET的返回值就不是204 */ try { URL url = new URL(mUrl); urlConnection = (HttpURLConnection) url.openConnection(); urlConnection.setInstanceFollowRedirects(false); urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS); urlConnection.setReadTimeout(SOCKET_TIMEOUT_MS); urlConnection.setUseCaches(false); urlConnection.getInputStream(); return urlConnection.getResponseCode() != 204; }...... } ~~~ 處理完畢后,CaptivePortalTracker將轉入ActiveNetworkState狀態。該狀態的內容非常簡單,讀者可自行閱讀它。由于筆者家中所在小區寬帶提供商使用了Capive Portal Check,所以筆者利用AirPcap截獲了相關網絡交換數據,如圖5-8所示: :-: ![](http://img.blog.csdn.net/20140309211006531?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSW5ub3N0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 圖5-8 Captive Portal Check示意圖 測試時,筆者禁用了無線網絡安全,所以AirPcap可以解析這些沒有加密的數據包。由圖5-8可知,當筆者的Note 2發起HTTP GET請求后,小區寬帶服務器回復了HTTP 302,所以筆者手機狀態欄才會顯然如圖5-9所示的提示項以提醒筆者該無線網絡需要登錄。 :-: ![](http://img.blog.csdn.net/20140309211102218?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSW5ub3N0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 圖5-9 Captive Portal Check提示示意圖 **4、CaptivePortalTracker總結和討論** 和WifiWatchdogStateMachine一樣,CaptivePortalTracker也比較有意思。CaptivePortalTracker類出現于4.2中。而4.1中的Captive Portacl Check功能則是由WifiWatchdogStateMachin來完成的。在4.1中,WifiWatchdogStateMachine定義了一個名為WalledGardenCheckState的類用于處理Captive Portal Check。 不過,筆者在研究4.1和4.2相關模塊的代碼后,發現4.2中的處理似乎有一些問題。此處先記下此問題,希望有興趣的讀者參與討論。該問題如下: * * * * * 4.2中,WifiStateMachine在ConnectedState前增加了一個CaptivePortalCheckState。很明顯,CaptivePortalCheckState的目的是在WifiStateMachine轉入ConnectedState之前完成Captive Portal Check。但根據本節對CaptivePortalTracker的介紹,只有WifiStateMachine進入ConnectedState后,ConnectivityService才會發送CONNECTIVITY_ACTION廣播。而在4.1中,WifiWatchdogStateMachine也是在WifiStateMachine轉入ConnectedState后進入WalledGardenCheckState的。 * * * * * >[info] 提示:那么,WifiStateMachine如何從CaptivePortalCheckState轉為ConnectedState呢? > > 答案在ConnectivityService的handleCaptivePortalTrackerCheck函數中。在那里,WifiStateMachine的captivePortalCheckComplete函數最終會被調用。在那個函數中,CMD_CAPTIVE_CHECK_COMPLETE將被發送,故CaptivePortalCheckState才會轉入ConnectedState狀態。但是,在這個流程中,CaptivePortalTracker并未被真正觸發以進行Captive Portal Check。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看