安卓学习24 -- 网络

1 整体架构

(出处见水印)

 这两张是能找到的比较清楚的图。目前可以看出,底层的网络业务,还是传统的linux内核提供。(注:这两个图我个人觉得不是非常对。。。

在安卓上增加的两个比较重要的部分分别是ConnectivityService和netd。这两个都是在system分区。通过socket和底层通信。

system分区和vendor分区区别如下:

分区功能
system(AOSP)提供标准的网络服务,如 ConnectivityService。同时,传统的linux网络服务比如DNS,iptables,routers等也在system分区。
vendor实现 HAL,比如 Wifi HAL、RIL(Radio Interface Layer),5G HAL
init.rc控制 netd 启动、网络接口初始化

ConnectivityService提供上层封装给app,通过binder连接netd,netd封装了底层网络功能和驱动HAL。

2 ConnectivityManager/ConnectivityService

2.1 ConnectivityManager

使用还是比较简单,在app层主要就是ConnectivityManager,不过这里只能获取一些网络信息。
API文档:https://developer.android.com/reference/android/net/ConnectivityManage

下面是一些示例代码。

package com.example.connectivitytest;

import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.content.Context;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import android.net.NetworkCapabilities;

public class MainActivity extends AppCompatActivity {
    private TextView networkStatus;
    private TextView networkStatus1;
    private TextView networkStatus2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        networkStatus = findViewById(R.id.network_status);

        ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
        if (cm != null) {
            NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
            boolean isConnected = activeNetwork != null && activeNetwork.isConnected();

            if (isConnected) {
                String type = activeNetwork.getType() == ConnectivityManager.TYPE_WIFI ? "Wi-Fi" : "Mobile Data";
                networkStatus.setText("Connected via: " + type);
            } else {
                networkStatus.setText("Not Connected");
            }
        } else {
            networkStatus.setText("ConnectivityManager unavailable");
        }

        NetworkCapabilities capabilities = cm.getNetworkCapabilities(cm.getActiveNetwork());
        boolean hasInternet = capabilities != null &&
                capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);

        networkStatus1 = findViewById(R.id.network_status1);
        if(hasInternet) {
            networkStatus1.setText("Has Internet");
        }

        networkStatus2 = findViewById(R.id.network_status2);
        Network[] allNetworks = cm.getAllNetworks();
        String info = "Network Info :";
        for (Network network : allNetworks) {
            NetworkCapabilities caps = cm.getNetworkCapabilities(network);
            //Log.d("Network Info", caps.toString());
            info += caps.toString();
        }
        networkStatus2.setText(info);
    }
}

在上层还有一些,比如WifiManager、TelephonyManager。

2.2 ConnectivityService

提供了上层很多自动控制功能。比如自动网络切换,自动VPN,节省流程等等。很多针对网络的控制逻辑是在这个部分处理。

这下面内容还是挺多。

常用命令

# 查看当前网络状态
adb shell dumpsys connectivity

# 监控网络事件
adb shell dumpsys connectivity event

# 检查NetworkPolicy
adb shell dumpsys netpolicy

在这一层,可以动态监测丢包率,从而控制应用使用不同的带宽。

3 netd

3.1 整体说明

在安卓的网络结构中,netd处在更核心的位置。netd的位置大致如下: 

 

netd 提供的内容如下:
防火墙配置(iptables):netd 负责配置和管理防火墙规则。它通过 iptables 命令来处理传入和传出的网络流量。

它还管理 NAT(网络地址转换)和数据包过滤功能。

DNS 配置:netd 负责管理 DNS 配置,包括配置 DNS 服务器和处理 DNS 查询。

IP 地址管理:它管理设备的网络接口,分配和管理 IP 地址等。例如,当设备连接到 Wi-Fi 或蜂窝网络时,netd 会分配 IP 地址。

网络路由管理:netd 配置并管理网络路由规则,确定数据包的转发路径。

VPN 管理:它处理与 VPN 相关的操作,包括路由网络流量、配置 VPN 接口等。

网络统计和监控:netd 提供了对网络连接、数据流量、接口状态等的统计和监控能力。

代码是在system/netd/,下载了一下代码,也不是太多东西,如下:

 主要还是server里面的东西

 瞟了一眼大概就是除了binder的内容,就是firewall,interface,iptables,netlink,router这就几个老同志。

3.2 iptables

IptablesProcess* IptablesRestoreController::forkAndExec(const IptablesProcessType type) {
    const char* const cmd = (type == IPTABLES_PROCESS) ?
        IPTABLES_RESTORE_PATH : IP6TABLES_RESTORE_PATH;

    // Create the pipes we'll use for communication with the child
    // process. One each for the child's in, out and err files.
    int stdin_pipe[2];
    int stdout_pipe[2];
    int stderr_pipe[2];

    // Assumes stdin, stdout, stderr are already in use.
    if (pipe2(stdin_pipe,  O_CLOEXEC) == -1 ||
        pipe2(stdout_pipe, O_NONBLOCK | O_CLOEXEC) == -1 ||
        pipe2(stderr_pipe, O_NONBLOCK | O_CLOEXEC) == -1) {

        ALOGE("pipe2() failed: %s", strerror(errno));
        return nullptr;
    }

    const auto& sys = sSyscalls.get();
    StatusOr<pid_t> child_pid = sys.fork();
    if (!isOk(child_pid)) {
        ALOGE("fork() failed: %s", strerror(child_pid.status().code()));
        return nullptr;
    }

    if (child_pid.value() == 0) {
        // The child process. Reads from stdin, writes to stderr and stdout.

        // stdin_pipe[0] : The read end of the stdin pipe.
        // stdout_pipe[1] : The write end of the stdout pipe.
        // stderr_pipe[1] : The write end of the stderr pipe.
        // Note: dup2 does not set O_CLOEXEC. std*_pipe[*] is closed by execl.
        if (dup2(stdin_pipe[0], 0) == -1 ||
            dup2(stdout_pipe[1], 1) == -1 ||
            dup2(stderr_pipe[1], 2) == -1) {
            ALOGE("dup2() failed: %s", strerror(errno));
            abort();
        }

        if (execl(cmd,
                  cmd,
                  "--noflush",  // Don't flush the whole table.
                  "-w",         // Wait instead of failing if the lock is held.
                  "-v",         // Verbose mode, to make sure our ping is echoed
                                // back to us.
                  nullptr) == -1) {
            ALOGE("execl(%s, ...) failed: %s", cmd, strerror(errno));
            abort();
        }

        // This statement is unreachable. We abort() upon error, and execl
        // if everything goes well.
        return nullptr;
    }

    // The parent process.

    if (close(stdin_pipe[0]) == -1 ||
        close(stdout_pipe[1]) == -1 ||
        close(stderr_pipe[1]) == -1) {
        ALOGW("close() failed: %s", strerror(errno));
    }

    // stdin_pipe[1] : The write end of the stdin pipe.
    // stdout_pipe[0] : The read end of the stdout pipe.
    // stderr_pipe[0] : The read end of the stderr pipe.
    return new IptablesProcess(type,
            child_pid.value(), stdin_pipe[1], stdout_pipe[0], stderr_pipe[0]);
}

可以看出就是调用的iptables-restore命令。

3.3 interface接口

// Run @fn on each interface as well as 'default' in the path @dirname.
void forEachInterface(
        const std::string& dirname,
        const std::function<void(const std::string& path, const std::string& iface)>& fn) {
    // Run on default, which controls the behavior of any interfaces that are created in the future.
    fn(dirname, "default");
    DIR* dir = opendir(dirname.c_str());
    if (!dir) {
        ALOGE("Can't list %s: %s", dirname.c_str(), strerror(errno));
        return;
    }
    while (true) {
        const dirent *ent = readdir(dir);
        if (!ent) {
            break;
        }
        if ((ent->d_type != DT_DIR) || !isInterfaceName(ent->d_name)) {
            continue;
        }
        fn(dirname, ent->d_name);
    }
    closedir(dir);
}

可以看出,还是直接用的linux的网络接口,从/proc/sys/net/ipv4/conf去获取数据

3.4 NDC

这个就是命令行下的netd操作工具。

网络接口

ndc interface list
ndc interface show eth0
ndc interface setcfg eth0 192.168.1.2 24 up
ndc interface getcfg eth0
ndc interface clearaddrs eth0

DNS

ndc resolver setnetdns <netId> <domain> <dns1> [dns2] ...
ndc resolver getnetdns <netId>
ndc resolver flushdefaultif

防火墙

ndc firewall enable
ndc firewall disable
ndc firewall set_interface_rule wlan0 allow
ndc firewall set_uid_rule standby 1000 allow

网络策略

ndc bandwidth enable
ndc bandwidth disable
ndc bandwidth addnaughtyapps 10064
ndc bandwidth removenaughtyapps 10064

Tethering(共享网络)

ndc tether interface add rndis0
ndc tether interface remove rndis0
ndc tether start
ndc tether stop

其它。。。

4 其它的命令

工具用途
ip / ifconfig传统网络命令,底层操作网络接口
iptables / ip6tables控制防火墙规则
netstat / ss查看网络连接状态
ping / traceroute测试网络连通性
setprop / getprop设置和读取系统属性(部分 netd 配置通过属性控制)
logcat查看 netd 输出日志
strace / lsof调试辅助工具,查看 netd 打开的文件、socket 等

好了,就是简单看看,先这样吧。。。 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值