android网络底层实现,Androidapp指定网络发送数据包的实现与原理分析

android⽹络底层实现,Androidapp指定⽹络发送数据包的实现
乔伊斯与原理分析
APP 和 native 使⽤的说明
App 使⽤默认⽹络
在android 中 ⼀个app使⽤⽹络,须要在manifest 申请⼀下javascript
这种⽅式将使⽤default⽹络,好⽐WIFI 和 数据⽹络,android 同⼀个时间点,只能有⼀个default⽹络(这个默认⽹络实质是什么或者怎么实现的,后⾯分析netd的⽂章会写)java
那有没有⼀种⽅式能够不使⽤默认⽹络呢,好⽐使⽤⼀个专有的⽹络通道访问专有的服务,答案是有的
APP使⽤指定⽹络linux
经过 requestNetwork 申请⼀个⽹络
在NetworkCallback中的onAvailable的⽅法去调⽤bindProcessToNetwork 去bind这个⽹络
上两步后APP的⽹络流量将会⾛这个network,或者说⾛这个network 指定的 ⽹卡
补充说明⼀下 :NetworkRequest 在CS对应⼀个NetworkRequestInfo ,通常状况下⼀个NetworkRequestInfo对应了⼀个client进程
⼀个例⼦android
NetworkRequest request = new NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
不锈钢t型条.build();
mNetworkCallback = new ConnectivityManager.NetworkCallback() {
@Override
public void onAvailable(final Network network) {
runOnUiThread(new Runnable() {
@Override
public void run() {
// requires android.permission.INTERNET
if (!mConnectivityManager.bindProcessToNetwork(network)) {
} else {
Log.d(TAG, "Network available");
}
}天高
});
}
Native进程使⽤指定⽹络
#include “NetdClient.h” 此⽂件,此⽂件在netd的源码中,并动态连接libnetd_client.so ,注意必定是动态连接,
调⽤ setNetworkForProcess()
强调⼀下,必定是动态连接
原理分析
申请⽹络requestNetwork
//frameworks/base/core/java/android/net/ConnectivityManager.java
public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback) {
}
NetworkRequest 能够设置 TransportType 好⽐ TRANSPORT_CELLULAR或者 TRANSPORT_WIFI
NetworkRequest 能够设置NetworkCapabilities好⽐NET_CAPABILITY_INTERNET或者其余类型
这个⽅法可能致使⼀个新的Network的出现,对应ConnectivityService中就是⼀个NetworkAgentInfo,关于这⼀点另外⼀篇⽂章会详细的说⼀下,这⾥能够简单的认为⼀个NetworkAgentInfo表明⼀个⽹络通道
NetworkCallback ⾥⾯有⼀些回调,说明⼀下web
绑定⽹络 BindProcessToNetwork
public static boolean setProcessDefaultNetwork(Network network) {
int netId = (network == null) ? NETID_UNSET : networkId;
if (netId == BoundNetworkForProcess()) {
return true;
}
if (NetworkUtils.bindProcessToNetwork(netId)) {}
}
BindProcessToNetwork底层原理分析
bindProcessToNetwork ,这个⽅法经过jni的⽅式调⽤了libnetd_client.so
⽤network中netId做为mark 设置到socket,致使app socket的数据包打上此mark,这个mark将会匹配到android的策略路由中,⾛到network对应⽹卡的路由表中.⽹络
例如network 的netId =101app
adb 查看策略路由dom
0: from all lookup local
9000: from all lookup main
10000: from all fwmark 0xc0000/0xd0000 lookup legacy_system
10500: from all oif dummy0 uidrange 0-0 lookup dummy0
10500: from all oif rmnet_data1 uidrange 0-0 lookup rmnet_data1
10500: from all oif rmnet_data0 uidrange 0-0 lookup rmnet_data0
10500: from all oif p2p0 uidrange 0-0 lookup local_network
13000: from all fwmark 0x10063/0x1ffff lookup local_network
13000: from all fwmark 0x10066/0x1ffff lookup rmnet_data1
13000: from all fwmark 0x10065/0x1ffff lookup rmnet_data0
注意这个 0x10065 ,就是101的16进制,就是说设置netid 101 mark的数据包会⾛到这条策略路由,进⽽经过rmnet_data⽹卡发送数据socket
问题思考
为何调⽤了setNetworkForProcess ,以后app⽆论采⽤何种⽅式的访问⽹络,好⽐okhttp 或者HttpURLConnection的原⽣⽅式都能路由到特定的⽹卡上呢ionic
⽆论采⽤⽅式,本质都使⽤了socket的,最终都会调⽤到sys/socket.h的socket(c库)
bionic/libc/include/sys/socket.h
#include 代码使⽤
int socket(int domain, int type, int protocol) {
return __netdClientDispatch.socket(domain, type, protocol);
}
__netdClientDispatch.socket 最初会被赋值为__socket(int, int, int);
extern "C" __socketcall int __socket(int, int, int);
多方会议
在__libc_preinit_impl 的时候会经过dlsym的⽅式调⽤/system/lib/libnetd_client.so中的netdClientSocket(前⾯说的要动态连接的缘由)
extern "C" void netdClientInitSocket(SocketFunctionType* function) {
if (function && *function) {
libcSocket = *function;
*function = netdClientSocket;
}}
netdClientInitSocket 执⾏后会使得 __netdClientDispatch.socket 被赋值为netdClientSocket ⽽libcSocket赋值为__scoket(系统调⽤)
Android app 和 native 建⽴的socket最终会调⽤到netClientSocket
int netdClientSocket(int domain, int type, int protocol) {
int socketFd;
#ifndef USE_WRAPPER
// 系统调⽤获得⼀个标准的socket
socketFd = libcSocket(domain, type, protocol);
#else
if( __propClientDispatch.propSocket ) {
socketFd = __propClientDispatch.propSocket(domain, type, protocol);
短期负荷预测} else {
socketFd = libcSocket(domain, type, protocol);
}
#endif
if (socketFd == -1) {
return -1;
}
unsigned netId = netIdForProcess;
// **将socket 打上 netId的mark**
if (netId != NETID_UNSET && FwmarkClient::shouldSetFwmark(domain)) {
if (int error = setNetworkForSocket(netId, socketFd)) {
return closeFdAndSetErrno(socketFd, error);
}
}
return socketFd;
}
在netdClientSocket建⽴的socket 会给socket打上netIdForProcess数值的mark,这个netIdForProcess其实就是bindProcessToNetwork 设置的netId,这样致使建⽴的socket都含有此mark,天然路由到netId对应的⽹卡了,hook的思想的体现!!
总结
再次感叹android的源码真⽜逼,设计的如此巧妙,修改了linux的c库,经过hook的⽅式,在app 建⽴的socket⾃动打上mark,实现了数据包的路由!!
全自动淘洗磁选机

本文发布于:2024-09-23 17:19:54,感谢您对本站的认可!

本文链接:https://www.17tex.com/xueshu/214742.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:设置   路由   能够   动态   数据包   实现   策略   说明
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议