Android5.0网络之多网络共存与应用

Android5.0之后,网络framework出现很大的变化,原生支持了以太网,并且支持多个网络同时连接同时存在。

Android5.0上面,并不是简单的网络共存,而是每个网络有一套自己的dns,网关,路由表。比如eth0,wlan0分别有自己独立的一套。应用层在建立socket连接的时候,可以自由选择使用那套网络。

下面看看Android是如何实现上述功能的

1. 独立保存的网络参数

Android5.0中引入和netid的概念,用它来标示不同的网络。ConnectivityService是Android的网络总管,负责系统上所有网络管理。当有dns,网关,路由表更新,就会由它设置到系统中并保存下来。

  1. private void updateDnses(LinkProperties newLp, LinkProperties oldLp, int netId, boolean flush) {  
  2. 3682         if (oldLp == null || (newLp.isIdenticalDnses(oldLp) == false)) {  
  3. 3683             Collection<InetAddress> dnses = newLp.getDnsServers();  
  4. 3684             if (dnses.size() == 0 && mDefaultDns != null) {  
  5. 3685                 dnses = new ArrayList();  
  6. 3686                 dnses.add(mDefaultDns);  
  7. 3687                 if (DBG) {  
  8. 3688                     loge("no dns provided for netId " + netId + ", so using defaults");  
  9. 3689                 }  
  10. 3690             }  
  11. 3691             if (DBG) log("Setting Dns servers for network " + netId + " to " + dnses);  
  12. 3692             try {  
  13. 3693                 mNetd.setDnsServersForNetwork(netId, NetworkUtils.makeStrings(dnses),  
  14. 3694                     newLp.getDomains());  
  15. 3695             } catch (Exception e) {  
  16. 3696                 loge("Exception in setDnsServersForNetwork: " + e);  
  17. 3697             }  
  18. 3698             NetworkAgentInfo defaultNai = mNetworkForRequestId.get(mDefaultRequest.requestId);  
  19. 3699             if (defaultNai != null && defaultNai.network.netId == netId) {  
  20. 3700                 setDefaultDnsSystemProperties(dnses);  
  21. 3701             }  
  22. 3702             flushVmDnsCache();  
  23. 3703         } else if (flush) {  
  24. 3704             try {  
  25. 3705                 mNetd.flushNetworkDnsCache(netId);  
  26. 3706             } catch (Exception e) {  
  27. 3707                 loge("Exception in flushNetworkDnsCache: " + e);  
  28. 3708             }  
  29. 3709             flushVmDnsCache();  
  30. 3710         }  
  31. 3711     }  
private void updateDnses(LinkProperties newLp, LinkProperties oldLp, int netId, boolean flush) {
3682         if (oldLp == null || (newLp.isIdenticalDnses(oldLp) == false)) {
3683             Collection<InetAddress> dnses = newLp.getDnsServers();
3684             if (dnses.size() == 0 && mDefaultDns != null) {
3685                 dnses = new ArrayList();
3686                 dnses.add(mDefaultDns);
3687                 if (DBG) {
3688                     loge("no dns provided for netId " + netId + ", so using defaults");
3689                 }
3690             }
3691             if (DBG) log("Setting Dns servers for network " + netId + " to " + dnses);
3692             try {
3693                 mNetd.setDnsServersForNetwork(netId, NetworkUtils.makeStrings(dnses),
3694                     newLp.getDomains());
3695             } catch (Exception e) {
3696                 loge("Exception in setDnsServersForNetwork: " + e);
3697             }
3698             NetworkAgentInfo defaultNai = mNetworkForRequestId.get(mDefaultRequest.requestId);
3699             if (defaultNai != null && defaultNai.network.netId == netId) {
3700                 setDefaultDnsSystemProperties(dnses);
3701             }
3702             flushVmDnsCache();
3703         } else if (flush) {
3704             try {
3705                 mNetd.flushNetworkDnsCache(netId);
3706             } catch (Exception e) {
3707                 loge("Exception in flushNetworkDnsCache: " + e);
3708             }
3709             flushVmDnsCache();
3710         }
3711     }
updateDnses会调用setDnsServersForNetwork来设置dns

NetworkManagementService.Java

  1. public void setDnsServersForNetwork(int netId, String[] servers, String domains) {  
  2. 1700         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);   
  3. 1701                                                                                                                                                                          
  4. 1702         final Command cmd = new Command("resolver""setnetdns", netId,  
  5. 1703                 (domains == null ? "" : domains));  
  6. 1704   
  7. 1705         for (String s : servers) {  
  8. 1706             InetAddress a = NetworkUtils.numericToInetAddress(s);  
  9. 1707             if (a.isAnyLocalAddress() == false) {  
  10. 1708                 cmd.appendArg(a.getHostAddress());  
  11. 1709             }     
  12. 1710         }     
  13. 1711               
  14. 1712         try {  
  15. 1713             mConnector.execute(cmd);  
  16. 1714         } catch (NativeDaemonConnectorException e) {  
  17. 1715             throw e.rethrowAsParcelableException();  
  18. 1716         }         
  19. 1717     }    
public void setDnsServersForNetwork(int netId, String[] servers, String domains) {
1700         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 
1701                                                                                                                                                                        
1702         final Command cmd = new Command("resolver", "setnetdns", netId,
1703                 (domains == null ? "" : domains));
1704 
1705         for (String s : servers) {
1706             InetAddress a = NetworkUtils.numericToInetAddress(s);
1707             if (a.isAnyLocalAddress() == false) {
1708                 cmd.appendArg(a.getHostAddress());
1709             }   
1710         }   
1711             
1712         try {
1713             mConnector.execute(cmd);
1714         } catch (NativeDaemonConnectorException e) {
1715             throw e.rethrowAsParcelableException();
1716         }       
1717     }  
上面的实现是将一组命令通过socket发送出去,接收端其实是netd中的CommandListener

CommandListener.cpp

  1. CommandListener::ResolverCmd::ResolverCmd() :  
  2.  773         NetdCommand("resolver") {  
  3.  774 }  
  4.   
  5. int CommandListener::ResolverCmd::runCommand(SocketClient *cli, int argc, char **margv) {  
  6.  777     int rc = 0;  
  7.  778     const char **argv = const_cast<const char **>(margv);  
  8.  779   
  9.  780     if (argc < 2) {  
  10.  781         cli->sendMsg(ResponseCode::CommandSyntaxError, "Resolver missing arguments"false);  
  11.  782         return 0;  
  12.  783     }  
  13.  784   
  14.  785     if (!strcmp(argv[1], "setnetdns")) {  
  15.  786         // "resolver setnetdns <netId> <domains> <dns1> <dns2> ..."  
  16.  787         if (argc >= 5) {  
  17.  788             rc = sResolverCtrl->setDnsServers(strtoul(argv[2], NULL, 0), argv[3], &argv[4], argc - 4);  
  18.  789         } else {  
  19.  790             cli->sendMsg(ResponseCode::CommandSyntaxError,  
  20.  791                     "Wrong number of arguments to resolver setnetdns"false);  
  21.  792             return 0;  
  22.  793         }  
  23.  794     } else if (!strcmp(argv[1], "flushnet")) { // "resolver flushnet <netId>"  
  24.  795         if (argc == 3) {  
  25.  796             rc = sResolverCtrl->flushDnsCache(strtoul(argv[2], NULL, 0));  
  26.  797         } else {  
  27.  798             cli->sendMsg(ResponseCode::CommandSyntaxError,  
  28.  799                     "Wrong number of arguments to resolver flushnet"false);  
  29.  800             return 0;  
  30.  801         }  
  31.  802     } else {  
  32.  803         cli->sendMsg(ResponseCode::CommandSyntaxError,"Resolver unknown command"false);  
  33.  804         return 0;  
  34.  805     }  
  35.  806   
  36.  807     if (!rc) {  
  37.  808         cli->sendMsg(ResponseCode::CommandOkay, "Resolver command succeeded"false);  
  38.  809     } else {  
  39.  810         cli->sendMsg(ResponseCode::OperationFailed, "Resolver command failed"true);  
  40.  811     }  
  41.  812   
  42.  813     return 0;  
  43.  814 }  
CommandListener::ResolverCmd::ResolverCmd() :
 773         NetdCommand("resolver") {
 774 }

int CommandListener::ResolverCmd::runCommand(SocketClient *cli, int argc, char **margv) {
 777     int rc = 0;
 778     const char **argv = const_cast<const char **>(margv);
 779 
 780     if (argc < 2) {
 781         cli->sendMsg(ResponseCode::CommandSyntaxError, "Resolver missing arguments", false);
 782         return 0;
 783     }
 784 
 785     if (!strcmp(argv[1], "setnetdns")) {
 786         // "resolver setnetdns <netId> <domains> <dns1> <dns2> ..."
 787         if (argc >= 5) {
 788             rc = sResolverCtrl->setDnsServers(strtoul(argv[2], NULL, 0), argv[3], &argv[4], argc - 4);
 789         } else {
 790             cli->sendMsg(ResponseCode::CommandSyntaxError,
 791                     "Wrong number of arguments to resolver setnetdns", false);
 792             return 0;
 793         }
 794     } else if (!strcmp(argv[1], "flushnet")) { // "resolver flushnet <netId>"
 795         if (argc == 3) {
 796             rc = sResolverCtrl->flushDnsCache(strtoul(argv[2], NULL, 0));
 797         } else {
 798             cli->sendMsg(ResponseCode::CommandSyntaxError,
 799                     "Wrong number of arguments to resolver flushnet", false);
 800             return 0;
 801         }
 802     } else {
 803         cli->sendMsg(ResponseCode::CommandSyntaxError,"Resolver unknown command", false);
 804         return 0;
 805     }
 806 
 807     if (!rc) {
 808         cli->sendMsg(ResponseCode::CommandOkay, "Resolver command succeeded", false);
 809     } else {
 810         cli->sendMsg(ResponseCode::OperationFailed, "Resolver command failed", true);
 811     }
 812 
 813     return 0;
 814 }
这里会最终通过调用netd的ResolverConntroller的setDnsServers来完成,setDnsServers里面调用bionic中函数__resolv_set_nameservers_for_net完成dns与netid的绑定和dns的存储。网关和路由的过程与dns类似,这里就不列举。只是要知道,系统中为每个网络保持了一份独立的网络参数(dns,路由,网关,代理等),并用netid与之映射。


2. 自由选择要使用的网络

下面这个api可以完成选择指定网络的功能

ConnectivityManager.java

  1. public static boolean setProcessDefaultNetwork(Network network) {  
  2. 2499         int netId = (network == null) ? NETID_UNSET : network.netId;                                                                                                     
  3. 2500         if (netId == NetworkUtils.getNetworkBoundToProcess()) {  
  4. 2501             return true;  
  5. 2502         }  
  6. 2503         if (NetworkUtils.bindProcessToNetwork(netId)) {  
  7. 2504             Log.d(TAG, "setProcessDefaultNetwork  netId: " + netId);  
  8. 2505             // Must flush DNS cache as new network may have different DNS resolutions.  
  9. 2506             InetAddress.clearDnsCache();  
  10. 2507             // Must flush socket pool as idle sockets will be bound to previous network and may  
  11. 2508             // cause subsequent fetches to be performed on old network.  
  12. 2509             NetworkEventDispatcher.getInstance().onNetworkConfigurationChanged();  
  13. 2510             return true;  
  14. 2511         } else {  
  15. 2512             return false;  
  16. 2513         }  
  17. 2514     }  
public static boolean setProcessDefaultNetwork(Network network) {
2499         int netId = (network == null) ? NETID_UNSET : network.netId;                                                                                                   
2500         if (netId == NetworkUtils.getNetworkBoundToProcess()) {
2501             return true;
2502         }
2503         if (NetworkUtils.bindProcessToNetwork(netId)) {
2504             Log.d(TAG, "setProcessDefaultNetwork  netId: " + netId);
2505             // Must flush DNS cache as new network may have different DNS resolutions.
2506             InetAddress.clearDnsCache();
2507             // Must flush socket pool as idle sockets will be bound to previous network and may
2508             // cause subsequent fetches to be performed on old network.
2509             NetworkEventDispatcher.getInstance().onNetworkConfigurationChanged();
2510             return true;
2511         } else {
2512             return false;
2513         }
2514     }
这个api最终会调用到netd

NetdClient.cpp

  1. extern "C" int setNetworkForProcess(unsigned netId) {                                                                                                                     
  2. 192     return setNetworkForTarget(netId, &netIdForProcess);  
  3. 193 }  
extern "C" int setNetworkForProcess(unsigned netId) {                                                                                                                   
192     return setNetworkForTarget(netId, &netIdForProcess);
193 }

  1. int setNetworkForTarget(unsigned netId, std::atomic_uint* target) {  
  2. 112     if (netId == NETID_UNSET) {  
  3. 113         *target = netId;  
  4. 114         return 0;  
  5. 115     }  
  6. 116     // Verify that we are allowed to use |netId|, by creating a socket and trying to have it marked  
  7. 117     // with the netId. Call libcSocket() directly; else the socket creation (via netdClientSocket())  
  8. 118     // might itself cause another check with the fwmark server, which would be wasteful.  
  9. 119     int socketFd;  
  10. 120     if (libcSocket) {  
  11. 121         socketFd = libcSocket(AF_INET6, SOCK_DGRAM, 0);  
  12. 122     } else {  
  13. 123         socketFd = socket(AF_INET6, SOCK_DGRAM, 0);  
  14. 124     }  
  15. 125     if (socketFd < 0) {  
  16. 126         return -errno;  
  17. 127     }  
  18. 128     int error = setNetworkForSocket(netId, socketFd);  
  19. 129     if (!error) {  
  20. 130         *target = netId;  
  21. 131     }  
  22. 132     close(socketFd);  
  23. 133     return error;  
  24. 134 }  
int setNetworkForTarget(unsigned netId, std::atomic_uint* target) {
112     if (netId == NETID_UNSET) {
113         *target = netId;
114         return 0;
115     }
116     // Verify that we are allowed to use |netId|, by creating a socket and trying to have it marked
117     // with the netId. Call libcSocket() directly; else the socket creation (via netdClientSocket())
118     // might itself cause another check with the fwmark server, which would be wasteful.
119     int socketFd;
120     if (libcSocket) {
121         socketFd = libcSocket(AF_INET6, SOCK_DGRAM, 0);
122     } else {
123         socketFd = socket(AF_INET6, SOCK_DGRAM, 0);
124     }
125     if (socketFd < 0) {
126         return -errno;
127     }
128     int error = setNetworkForSocket(netId, socketFd);
129     if (!error) {
130         *target = netId;
131     }
132     close(socketFd);
133     return error;
134 }

上面这段主要作用是对netIdForProcess赋值


当应用建立socket的时候会调用到下面这个api

NetdClient.cpp

  1. int netdClientSocket(int domain, int type, int protocol) {  
  2.  86     int socketFd = libcSocket(domain, type, protocol);  
  3.  87     if (socketFd == -1) {             
  4.  88         return -1;  
  5.  89     }  
  6.  90     unsigned netId = netIdForProcess;  
  7.  92     if (netId != NETID_UNSET && FwmarkClient::shouldSetFwmark(domain)) {   
  8.  93         if (int error = setNetworkForSocket(netId, socketFd)) {  
  9.  94             return closeFdAndSetErrno(socketFd, error);  
  10.  95         }  
  11.  96     }  
  12.  97     return socketFd;                                                                                                                                                      
  13.  98 }                
int netdClientSocket(int domain, int type, int protocol) {
 86     int socketFd = libcSocket(domain, type, protocol);
 87     if (socketFd == -1) {           
 88         return -1;
 89     }
 90     unsigned netId = netIdForProcess;
 92     if (netId != NETID_UNSET && FwmarkClient::shouldSetFwmark(domain)) { 
 93         if (int error = setNetworkForSocket(netId, socketFd)) {
 94             return closeFdAndSetErrno(socketFd, error);
 95         }
 96     }
 97     return socketFd;                                                                                                                                                    
 98 }              
这里netIdForProcess就是前面设置下来的,因为它的值不再是NETID_UNSET,导致条件满足,调用到setNetworkForSocket

  1. extern "C" int setNetworkForSocket(unsigned netId, int socketFd) {                                                                                                        
  2. 184     if (socketFd < 0) {  
  3. 185         return -EBADF;  
  4. 186     }  
  5. 187     FwmarkCommand command = {FwmarkCommand::SELECT_NETWORK, netId, 0};  
  6. 188     return FwmarkClient().send(&command, sizeof(command), socketFd);  
  7. 189 }  
extern "C" int setNetworkForSocket(unsigned netId, int socketFd) {                                                                                                      
184     if (socketFd < 0) {
185         return -EBADF;
186     }
187     FwmarkCommand command = {FwmarkCommand::SELECT_NETWORK, netId, 0};
188     return FwmarkClient().send(&command, sizeof(command), socketFd);
189 }
这个function最终将netId通过本地socket发送出去,结果由FwmakrServer接收并处理

  1.         case FwmarkCommand::SELECT_NETWORK: {                                                                                                                             
  2. 155             fwmark.netId = command.netId;  
  3. 156             if (command.netId == NETID_UNSET) {  
  4. 157                 fwmark.explicitlySelected = false;  
  5. 158                 fwmark.protectedFromVpn = false;  
  6. 159                 permission = PERMISSION_NONE;  
  7. 160             } else {  
  8. 161                 if (int ret = mNetworkController->checkUserNetworkAccess(client->getUid(),  
  9. 162                                                                          command.netId)) {  
  10. 163                     return ret;  
  11. 164                 }  
  12. 165                 fwmark.explicitlySelected = true;  
  13. 166                 fwmark.protectedFromVpn = mNetworkController->canProtect(client->getUid());  
  14. 167             }  
  15. 168             break;  
  16. 169         }  
        case FwmarkCommand::SELECT_NETWORK: {                                                                                                                           
155             fwmark.netId = command.netId;
156             if (command.netId == NETID_UNSET) {
157                 fwmark.explicitlySelected = false;
158                 fwmark.protectedFromVpn = false;
159                 permission = PERMISSION_NONE;
160             } else {
161                 if (int ret = mNetworkController->checkUserNetworkAccess(client->getUid(),
162                                                                          command.netId)) {
163                     return ret;
164                 }
165                 fwmark.explicitlySelected = true;
166                 fwmark.protectedFromVpn = mNetworkController->canProtect(client->getUid());
167             }
168             break;
169         }
  1. fwmark.permission = permission;                                                                                                                                       
  2. 206     if (setsockopt(*socketFd, SOL_SOCKET, SO_MARK, &fwmark.intValue,  
  3. 207                    sizeof(fwmark.intValue)) == -1) {  
  4. 208         return -errno;  
  5. 209     }  
上面的处理中,首先会将netid赋值给fwmark,最后通过setsocketopt将fwmark设置到socket中,这样就为建立的socket设置了mark。下面就是看如何使用mark。

在每个网络建立起来后,系统都会为其建立一条路由规则。下图是Android系统中所有的路由规则



以下面这条路由规则为例:



0x10064其中0x64(十进制为100)就是该网络的netid,如果应用选择在这个网络上建立socket,那么通过上面那些步骤建立的socket,就会被带有0x64的mark,这样当改socket输出数据时候,就会被上面的路由规则捕获,从而使用eth0这个路由表。

下面是eth0路由表的内容










  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值