1. 程式人生 > >Android推送註冊失敗問題排查

Android推送註冊失敗問題排查

最近專案在生產環境上發現有android手機無法連上推送伺服器的現象,導致推送無法正常使用。經過之後專案組一系列的排查之後,基本鎖定問題原因,下面就是介紹下問題的現象及排查步驟。

現象
生產環境上,如使用3G/4G網路時Android手機無法收到推送訊息。但如果切換到行內wifi時,則能正常收到推送。在測試環境上無此現象,一切正常。

排查流程
1、通過客戶端日誌發現,在使用3G/4G網路時,手機在連線ejabberd推送伺服器時註冊失敗,並不斷重新連線。但具體失敗原因從客戶端日誌中無法確定。
2、然後去檢視ejabberd的日誌,如下圖所示
這裡寫圖片描述
圖1 註冊失敗日誌
從日誌上看,並沒發現任何報錯或異常資訊,只是看到ejabberd在收到客戶端傳送的starttls請求之後再也沒收到其他任何請求。
為了對比成功和失敗兩種情況的日誌,我們使用行內wifi,得到如下日誌。
這裡寫圖片描述


圖2 註冊成功日誌(上)
這裡寫圖片描述
圖3 註冊成功日誌(下)
這兩張圖是同一個日誌的兩頁,需要連起來看。可以發現在starttls請求之後ejabberd還會收到客戶端重新初始化的stream流、使用者名稱密碼等資訊。
通過比較得出的結論:連線中斷是發生在starttls和重新初始化stream流之間的環節。

3、由於沒有更多的日誌資訊,客戶端只能做各種更改配置的測試。其中客戶端在跳過tls驗證時,發現就能成功連上。客戶端的配置修改如下:
connConfig.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled);
因此得出結論,問題出在tls驗證這塊。

4、由於客戶端和服務端程式碼都沒改動的情況下,使用行方wifi就成功,使用非行方網路就失敗,因此我們懷疑可能是行方網路問題導致,可能在某些網路裝置中加了某些網路策略,把tls驗證的連線掐斷了。諮詢行方後,行方也認為有可能,但不敢確定,建議我們抓包分析。

5、於是在公網中分別抓了成功和失敗的包,如下圖所示。
這裡寫圖片描述
圖4 成功時的包

這裡寫圖片描述
圖5 失敗時的包
從圖4可以看到,在TLS握手過程中,客戶端向ejabberd傳送Client Hello請求後,後面會有個ejabberd的Server Hello、certificate、server hello done應答包;而對比圖5,發現ejabberd沒有返回Server Hello包,而是回了個結束TCP會話的Reset包,從而導致整個TLS握手沒有成功,TCP連線中斷。
從這裡可以得出結論,伺服器端沒有響應Client Hello,併發了箇中斷會話的包導致握手失敗。更加確定是網路策略或防火牆原因導致。
6、之後又從伺服器的閘道器處進行抓包,如下圖所示。(說明下,圖5和圖6是同一個請求,只是抓包的位置不同。圖5在公網中抓的包,圖6在內網中抓的。)
這裡寫圖片描述


圖6 閘道器處失敗時的包
由於抓包工具不同,圖6的顯示略顯不同。觀察圖6,第55個包是Client Hello的請求包,第57個是Reset包,粗看和圖5差不多,但細看會發現兩個問題:1、多了第56個包,圖5上沒有類似的包。對比圖4和分析它的長度、內容後我們基本確定第56個包應該是伺服器返回的Server Hello包;2、第57個的Reset包對比圖5上的Reset包發現,他們的源、目地址不同,正好相反。也就是說圖5是伺服器告訴客戶端TCP請求中斷了,而圖6是客戶端告訴伺服器TCP請求中斷了。
請教網路工程師分析後得出結論:
針對問題1,伺服器已經返回Server Hello的包,但是由於某些原因(如被網路策略攔截、防火牆等)沒有正確的傳送到公網中,因此在公網中沒抓到。
針對問題2,如果確實中間有裝置把這一請求中斷,那作為中間方會對兩邊(客戶端和伺服器)都會發送一個RST包,那對於客戶端來說,中間方是伺服器,因此源地址是伺服器地址;伺服器情況就相反。
也就是說我們的猜測完全能解釋清楚這兩個問題。
7、把這一分析結果給行方網路部後,他們就嘗試了下把伺服器ip加入網路裝置的直通名單中,測試後發現問題解決。

經驗分享
分析過程一波三折,為了排查問題走了很多彎路。其中收穫了幾點經驗:
1、如果從日誌上看不到有價值的資訊,建議通過抓包的方式查詢問題。
2、特別是生產環境問題排查,抓包需要在內外網同時抓,然後對比,可以很大程度上排除網路方面的原因。
3、由於不瞭解網路的結構,建議把抓到的包請相關網路人員分析,能更快得出結論。