android ip探测,Android-IpReachabilityMonitor
簡介
本文主要介紹基于Android 7.0 的IpReachabilityMonitor機制
IpReachabilityMonitor簡介* Monitors on-link IP reachability and notifies callers whenever any on-link addresses of interest appear to have become unresponsive.
//監視鏈路IP的可達性;無論任何時候,一旦所關注的鏈路地址變的不響應時,就會通知調用者。This code does not concern itself with "why" a neighbour might have become unreachable. Instead, it primarily reacts to the kernel's notion of IP reachability for each of the neighbours we know to be critically important to normal network connectivity. As such, it is often "just the messenger":the neighbours about which it warns are already deemed by the kernel to have become unreachable.
//IpReachabilityMonitor的代碼實現邏輯不關心為什么一個neighbour網絡變為不可達。相反,他主要反映在內核層面中每一個neighbour網絡的IP可達性概念或狀態。我們知道這個IP可達性狀態對于正常網絡連接來說是關鍵重要的。因此,IpReachabilityMonitor通常僅是“信使”:它警告neighbours網絡已經被內核kernel視為不可達。
IpReachabilityMonitor工作方式
How it works:1. The "on-link neighbours of interest" found in a given LinkProperties instance are added to a "watch list" via #updateLinkProperties().This usually means all default gateways and any on-link DNS servers.
//1、在給定的LinkProperties實例中找到關注的鏈路neighbours網絡,這些neighbours網絡被通過updateLinkProperties()方法添加到一個"watch list"中。這通常意味著所有默認網關和鏈路DNS服務器。2. We listen continuously for netlink neighbour messages (RTM_NEWNEIGH,RTM_DELNEIGH), watching only for neighbours in the watch list.
//2、我們連續不斷地監聽netlink消息(RTM_NEWNEIGH,RTM_DELNEIGH),僅僅關注在watch list中的neighbours網絡。- A neighbour going into NUD_REACHABLE, NUD_STALE, NUD_DELAY, and even NUD_PROBE is perfectly normal; we merely record the new state.
//一個neighbour網絡進入NUD_REACHABLE, NUD_STALE, NUD_DELAY和NUD_PROBE狀態,均是完全正常現象,我們只是記錄最新的狀態。- A neighbour's entry may be deleted (RTM_DELNEIGH), for example due to garbage collection.? This is not necessarily of immediate concern; we record the neighbour as moving to NUD_NONE.
//一個neighbour條目可能被刪除(RTM_DELNEIGH),例如由于垃圾回收。這個沒有必要進行立即關聯。我們記錄被搬移到NUD_NONE狀態的neighbour網絡。- A neighbour transitioning to NUD_FAILED (for any reason) is? critically important and is handled as described below in #4.
//一個neighbour網絡被轉移到NUD_FAILED(任何原因)是極其重要的,這個相應的操作將會在下面#4描述。3. All on-link neighbours in the watch list can be forcibly "probed" by calling #probeAll(). This should be called whenever it is important to verify that critical neighbours on the link are still reachable, e.g. when roaming between BSSIDs.
//3、可以通過調用probeAll()方法來強制執行probed所有在watch list 中的鏈路neighbours網絡。不管什么時候,對于想驗證鏈路上關鍵neighbour網絡依然可達,這個方法是重要的,應該被調用,比如當在不同的BSSID之間Roaming的時候。- The kernel will send unicast ARP requests for IPv4 neighbours and unicast NS packets for IPv6 neighbours.? The expected replies will likely be unicast.
//內核kernel將為IPv4 neighbour 網絡發送單播ARP請求和為IPv6 neighbour網絡發送單播NS數據包。預期的答復可能是單播。- The forced probing is done holding a wakelock. The kernel may,however, initiate probing of a neighbor on its own, i.e. whenever a neighbour has expired from NUD_DELAY.
//強制probing 必須持有一個wakelock才可以執行。然而,內核kernel也許引發自己的一個neighbor
網絡的probing,比如一個neighbour網絡已經過期了(在進入NUD_DELAY狀態后過期)。- The kernel sends:
&1(/proc/sys/net/ipv{4,6}/neigh//ucast_solicit) number of probes (usually 3) every? ? ? ? &2(/proc/sys/net/ipv{4,6}/neigh//retrans_time_ms)number of milliseconds (usually 1000ms).
This normally results in 3 unicast packets, 1 per second.
//內核Kernel每&2秒發送&1次Probe 單播請求。通常結果是每1秒發送3次單播請求。- If no response is received to any of the probe packets, the kernel marks the neighbour as being in state NUD_FAILED, and the listening process in #2 will learn of it.
//如果對于所有的Probe 請求,都沒有接受到響應,內核kernel會將neighbour網絡標記為NUD_FAILED狀態,在#2中描述的監聽進程將會學習它。4. We call the supplied Callback#notifyLost() function if the loss of a neighbour in NUD_FAILED would cause IPv4 or IPv6 configuration to become incomplete (a loss of provisioning).
//4、如果處于NUD_FAILED狀態的neighbour網絡的丟失將會導致Ipv4 或者Ipv6配置變得不完整(配置丟失),我們將會調用提供的Callback#notifyLost()函數。- For example, losing all our IPv4 on-link DNS servers (or losing our only IPv6 default gateway) constitutes a loss of IPv4 (IPv6) provisioning; Callback#notifyLost() would be called.
//比如丟失所有IPv4鏈路DNS服務器(或者丟失僅有的Ipv6默認網關)會構成Ipv4(Ipv6)配置丟失。
Callback#notifyLost()函數將會被調用。- Since it can be non-trivial to reacquire certain IP provisioning state it may be best for the link to disconnect completely and reconnect afresh.
//因為重新獲取特定的IP配置狀態是非常重要的。最好的方式是完全斷開連接,然后進行重連。
IpReachabilityMonitor實現
1、在給定的LinkProperties實例中找到關注的鏈路neighbours網絡,這些neighbours網絡被通過updateLinkProperties()方法添加到一個"watch list"中。這通常意味著所有默認網關和鏈路DNS服務器。public void updateLinkProperties(LinkProperties lp)
mLinkProperties = new LinkProperties(lp);
MapnewIpWatchList= new HashMap<>();
final Listroutes = mLinkProperties.getRoutes();
//將處于鏈接狀態的默認網關加入IpWatchList
for (RouteInfo route : routes) {
if (route.hasGateway()) {
InetAddress gw = route.getGateway();
if (isOnLink(routes, gw)) {
newIpWatchList.put(gw, getNeighborStateLocked(gw);}} }
//將處于鏈接狀態的DNS服務器加入IpWatchList
for (InetAddress nameserver : lp.getDnsServers()) {
if (isOnLink(routes, nameserver)) {
newIpWatchList.put(nameserver, getNeighborStateLocked(nameserver));}}
mIpWatchList= newIpWatchList;
mIpWatchListVersion++;
2、我們連續不斷地監聽netlink消息(RTM_NEWNEIGH,RTM_DELNEIGH),僅僅關注在watch list中的neighbours網絡。public IpReachabilityMonitor(Context context, String ifName, Callback callback,
AvoidBadWifiTracker tracker) throws IllegalArgumentException {
...
//NetlinkSocketObserver類是用來建立Socket連接,不斷地接受來自kernel的netlink消息,并并解析消息,判讀是否加入IpWatchList中。具體信息可以參考下面NetlinkSocketObserver部分解析
mNetlinkSocketObserver = new NetlinkSocketObserver();
mObserverThread = new Thread(mNetlinkSocketObserver);
mObserverThread.start();
...
}
3、可以通過調用probeAll()方法來強制執行probed所有在watch list中的鏈路neighbours網絡。不管什么時候,對于想驗證鏈路上關鍵neighbour網絡依然可達,這個方法是重要的,應該被調用,比如當在不同的BSSID之間Roaming的時候。//將IpWatchList中Key集合取出來,然后通過調用probeNeighbor(int ifIndex, InetAddress ip)驗證相應的neighbour是否可達。
public void probeAll() {
//將IpWatchList中Key集合賦值給ipProbeList
Set? ipProbeList = new HashSet();
ipProbeList.addAll(mIpWatchList.keySet());
for (InetAddress target : ipProbeList) {
final int returnValue = probeNeighbor(mInterfaceIndex, target);
/// M: Add UDP packet for ARP retry
//下面是MTK添加的策略,針對probeNeighbor失敗的情況下,使用UDP重新觸發一次ARP請求
if (returnValue != 0) {
// Use UDP broadcast to trigger ARP procedure.
sendUdpBroadcast(target);}}}
private static int probeNeighbor(int ifIndex, InetAddress ip):
對于具體接口Index號上的給定Ip地址,使內核Kernel執行neighbour網絡可達性檢測(IPv4 ARP或 IPv6 ND)。
如果網絡可達性檢測請求成功傳輸到內核kernel,返回0; 其他返回一個非0的錯誤碼。private static int probeNeighbor(int ifIndex, InetAddress ip) {
...
//將ip地址和相應的接口號ifIndex封裝到PROBE消息中
final byte[] msg = RtNetlinkNeighborMessage.newNewNeighborMessage(
1, ip, StructNdMsg.NUD_PROBE, ifIndex, null);
//創建NetlinkSocket,成功后進行連接kernel, 然后發送消息;
最后接收消息,并通過Netlink對消息進行解析。
try (NetlinkSocket nlSocket = new NetlinkSocket(OsConstants.NETLINK_ROUTE)) {
nlSocket.connectToKernel();
nlSocket.sendMessage(msg, 0, msg.length, IO_TIMEOUT);
final ByteBuffer bytes = nlSocket.recvMessage(IO_TIMEOUT);
// recvMessage() guaranteed to not return null if it did not throw.
final NetlinkMessage response = NetlinkMessage.parse(bytes);
。。。//后面依據不同的response 返回不同的值。
}}
4、如果處于NUD_FAILED狀態的neighbour網絡的丟失將會導致Ipv4 或者Ipv6配置變得不完整(配置丟失),我們將會調用提供的Callback#notifyLost()函數。private void handleNeighborLost(String msg) {
LinkProperties whatIfLp = new LinkProperties(mLinkProperties);
for (Map.Entryentry : mIpWatchList.entrySet()) {
//遍歷IpWatchList中的所有neighbor,尋找value狀態為NUD_FAILED的
if (entry.getValue() != StructNdMsg.NUD_FAILED) {
continue;
}
//從IpWatchList找到了value狀態為NUD_FAILED的neighbor, 獲取其IP地址;
//遍歷mLinkProperties中路由Routes的網關是否有跟該IP地址一致的,如果有,則從當前的whatIfLp 中移除相應的路由Routes。
ip = entry.getKey();
for (RouteInfo route : mLinkProperties.getRoutes()) {
if (ip.equals(route.getGateway())) {
whatIfLp.removeRoute(route);
}
//如果該IP地址不是IPv6 地址或者使能了避免badLink連接的性能,則從whatIfLp中移除Ip地址對應的DNS服務器。
if (avoidingBadLinks() || !(ip instanceof Inet6Address)) {
// We should do this unconditionally, but alas we cannot: b/31827713.
whatIfLp.removeDnsServer(ip);
}
}
//調用LinkProperties的compareProvisioning函數得到whatIfLp與原始的mLinkProperties的區別。
delta = LinkProperties.compareProvisioning(mLinkProperties, whatIfLp);
//如果delta值為ProvisioningChange.LOST_PROVISIONING,則回調函數notifyLost進行配置丟失的處理;該回調函數的實現是在IpManager中,詳見IpManger中的分析。
if (delta == ProvisioningChange.LOST_PROVISIONING) {
mCallback.notifyLost(ip, logMsg);
}
}
Android - NetlinkSocketObserver
NetlinkSocketObserver簡介
在IpReachabilityMonitor類中有一個子類NetlinkSocketObserver類。
在IpReachiabilityMonitor 構造函數中會創建NetlinkSocketObserver對象,并對該對象進行封裝,創建一個Thread類 對象,并調用Thread類對象的Start方法,啟動線程。mNetlinkSocketObserver = new NetlinkSocketObserver();
mObserverThread = new Thread(mNetlinkSocketObserver);
mObserverThread.start();
NetlinkSocketObserver作用
NetlinkSocketObserver 類主要和Android Netlink 進行交互。Android netlink :frameworks/base/services/net/java/android/net/netlink/...
該類的作用主要是建立NETLINK_ROUTE Socket,綁定相應的NetlinkSocketAddress。然后無限循環接收kernelReply信息并對該消息進行解析。
NetlinkSocketObserver實現
//通過實現Runnable接口創建線程,重寫run方法;
該類的作用就是建立NETLINK_ROUTE Socket,綁定相應的NetlinkSocketAddress。然后無限循環接收kernelReply信息并對該消息進行解析。
關鍵接口實現:Run()
-->parseNetlinkMessageBuffer(byteBuffer, whenMs)
-->evaluateRtNetlinkNeighborMessage((RtNetlinkNeighborMessage) nlMsg, whenMs);private final class NetlinkSocketObserver implements Runnable
{
//建立NETLINK_ROUTE Socket,綁定相應的NetlinkSocketAddress。然后無限循環接收kernelReply信息并對該消息進行解析。public void run() {
//1、建立NETLINK_ROUTE Socket,并綁定bind 相應的NetlinkSocketAddress
setupNetlinkSocket();
//2、接收Kernel的Reply信息
byteBuffer = recvKernelReply();
//3、對接收到的KernelReply信息進行解析
parseNetlinkMessageBuffer(byteBuffer, whenMs);
}//將ByteBuffer解析為NetlinkMessage格式消息,并判斷消息類型,調用評估消息是否更新相應ipadress的IpWatchList。
private void parseNetlinkMessageBuffer(ByteBuffer byteBuffer, long whenMs)
/*
//1、通過調用NetlinkMessage類將ByteBuffer解析為NetlinkMessage格式消息
final NetlinkMessage nlMsg = NetlinkMessage.parse(byteBuffer);
//2、判斷解析出現的NetlinkMessage消息類型,確保是RtNetlinkNeighborMessage消息才繼續進行評估;如果是NetlinkErrorMessage或不是RtNetlinkNeighborMessage消息直接退出。
nlMsg instanceof NetlinkErrorMessage
nlMsg instanceof RtNetlinkNeighborMessage
//3、調用evaluateRtNetlinkNeighborMessage對RtNetlinkNeighborMessage消息進行評估。
evaluateRtNetlinkNeighborMessage((RtNetlinkNeighborMessage) nlMsg, whenMs);
*///依據從RtNetlinkNeighborMessage獲取的msgType和nudState,對IpWatchList中相應的InetAddress的nudState 進行更新。
private void evaluateRtNetlinkNeighborMessage
(RtNetlinkNeighborMessage neighMsg, long whenMs)
/*
//1、從neighMsg取目的IP地址,并判斷該IP地址是否在IpWatchList中,不在則直接退出函數返回
final InetAddress destination = neighMsg.getDestination();
//2、從neighMsg取msgType和nudState,并根據他們進行IpWatchList 的更新
final short msgType = neighMsg.getHeader().nlmsg_type;
final short nudState = ndMsg.ndm_state;
final short value =
(msgType == NetlinkConstants.RTM_DELNEIGH) ? StructNdMsg.NUD_NONE: nudState;
mIpWatchList.put(destination, value);
//3、如果nudState為NUD_FAILED狀態,則執行handleNeighborLost動作
if (nudState == StructNdMsg.NUD_FAILED) {
handleNeighborLost(eventMsg);? //這個詳見IpReachiabilityMonitor的實現方式的第4部分。
*/}
總結
以上是生活随笔為你收集整理的android ip探测,Android-IpReachabilityMonitor的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 除了鸿蒙还注册,除了“华为鸿蒙”,你不知
- 下一篇: 显示android缓存文件,androi