Android多网络并存

1 基本概念
1.1 Android任何网络类型
1)与netd打交道通过INetworkManagementService 
2)与ConnectivityService 打交道通过NetworkAgent

1.2 检查是否有网络连接
Java网络库API路径:Android_project/libcore
Android判断网络是否连接:
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
public static boolean isNetworkConnected(
    Context context) {
    if (context != null) {
        ConnectivityManager connectivityManager =
            (ConnectivityManager)context
            .getSystemService(
            Context.CONNECTIVITY_SERVICE);
        // Ethernet, WiFi, Mobile
        NetworkInfo networkInfo =
        connectivityManager.getActiveNetworkInfo();
        if (networkInfo != null) {
            return networkInfo.isAvailable();
        }
    }
    return false;
}

使用命令dumpsys connectivity查看激活的网络和该网络的得分。

1.3 实施方法
连接高优先级的网络,低优先级的不断开。
frameworks/base/services/core/java/com/android/server/ConnectivityService.java
private void
teardownUnneededNetwork(NetworkAgentInfo nai) {
    if (SystemProperties.getBoolean(
        "ro.net.coexist", false)) {
        return;
    }
    [...]
}

2 路由添加语法
ip route add {NETWORK/MASK} via {GATEWAYIP}
ip route add {NETWORK/MASK} dev {DEVICE}
ip route add default {NETWORK/MASK} dev {DEVICE}
ip route add default {NETWORK/MASK} via {GATEWAYIP}

ip route add default via 192.168.0.1 dev eth0 \
table 1

# ip rule add from all lookup main pref 9999
# 上一条命令等价于在netd中添加modifyIpRule(RTM_NEWRULE, 9999, 254, 0, 0);
ip rule add from 192.168.0.0/24 table 1
ip rule add to 192.168.0.0/24 table 1
table 1中包含了eth0默认网关,而table main中包含了正常的eth0路由。

3 Android netId
3.1 获取网络接口的netId
netd中将接口名(wlan0、eth0等)转化为netId的函数:
server/NetworkController.cpp
NetworkController::getNetworkForInterface(
    const char* interface)

3.2 代码示例
server/CommandListener.cpp
函数CommandListener::NetworkCommand::runCommand()的最后添加如下的代码:
//       0              1              2
// network query_netid if_name
if (!strcmp(argv[1], "query_netid")) {
    if (argc < 3) {
        return syntaxError(client,
            "Missing argument");
    }
    int _netId =
        gCtls->netCtrl.getNetworkForInterface(
            argv[2]);
    char msg[16] = {0};
    int retval = snprintf(msg, 15, "%d", _netId);
    if (retval > 0) {
        client->sendMsg(
            ResponseCode::CommandOkay,
            msg, false);
        return 0;
    } else {
        return operationError(client,
            "Can not get netId", retval);
    }
}
用法:ndc network query_netid wlan0

4 Android UID
4.1 Android-T fs_config
system/core/libcutils/include/private/android_filesystem_config.h
build/tools/fs_config
out/soong/.intermediates/bionic/libc/generated_android_ids/gen/generated_android_ids.h
Show string UID: ls -l /dev/xxx
Show numeric UID: ls -n /dev/xxx
chown 0:5008 /dev/xxx

4.2 UID查找方法
Android中,使用iptables绑定一个APP到特定的路由时,需要用到UID。
ps -A后每一行的第一个字符串表示UID,查看该UID对应的数值,使用id
例如:
id u0_a50

其中u0_a50的含义:
u0:默认的手机第一个用户
a:代表app
50:代表着第50个应用

转换公式:
u0_a50 = “u0_” + “a” + (uid(这里是10050) – FIRST_APPLICATION_UID(固定值10000))

4.3 UID查找脚本示例
#!/vendor/bin/sh

APP_LIST=("com.android.email"
 "com.android.systemui"
 "[email protected]")

SH_PS="/vendor/bin/ps"
SH_GREP="/vendor/bin/grep"
SH_ID="/vendor/bin/id"
SH_TR="/vendor/bin/tr"
SH_ECHO="/vendor/bin/echo"
SH_TEE="/vendor/bin/tee"
SH_USLP="/vendor/bin/usleep"

for app in ${APP_LIST[@]}
do
    count=1
    while [ $count -le 10 ]; do
        line=$($SH_PS -A | $SH_GREP ${app})
        if [ $? -eq 0 ]; then
            $SH_ECHO "got ${app}, count $count" \
                | $SH_TEE /dev/kmsg
            break
        fi

        $SH_ECHO "waiting ${app}, count $count" \
                | $SH_TEE /dev/kmsg
        $SH_USLP 500000
        count=$((count + 1))
    done

    line=$($SH_PS -A | $SH_GREP ${app})
    if [ $? -eq 0 ]; then
        list=(${line}) # switch str to list
        # len=${#list[@]} # length of list
        # len=$((len - 1))
        uid_str=${list[0]}

        line=$($SH_ID $uid_str)
        list=(${line}) # switch str to list
        uid_str=${list[0]}
        # uid=10017(u0_a17) -> uid=10017
        uid_str=${uid_str%\(*}

        uid=$($SH_ECHO $uid_str | \
            $SH_TR -cd "[0-9]")
        # Now got the process UID
        $SH_ECHO $uid | $SH_TEE /dev/kmsg
    fi
done

5 绑定某个应用到指定的网络
5.1 Linux netfilter hook
Linux内核网络代码被netfilter cut off的函数都分为了两个阶段:XXX以及XXX_finish。
struct nf_hook_ops
nf_register_net_hook()
nf_unregister_net_hook()

kernel IPv4 print: %pI4
user IPv4 print: inet_ntoa
meta|match1|match2|...|target

5.1.1 match
iptables -m xxx: xxx = kernel struct xt_match, libipt_xxx.so
net/netfilter/xt_owner.c
external/iptables/extensions/libxt_owner.c

5.1.2 target
iptables -j xxx: xxx = kernel struct xt_target, libipt_xxx.so

xt_register_target()
xt_unregister_target()

5.2 Android API
bindProcessToNetwork()
netd中hook了socket()、connect()和accept()等API。
bionic/libc/bionic/socket.cpp
bionic/libc/bionic/connect.cpp
system/netd/client/NetdClient.cpp
FwmarkClient::shouldSetFwmark(int family)

5.3 命令行方式
1)添加main rule
ip rule add from all lookup main pref 9999

2)为eth0接口添加VLAN ID 5
ip link add link eth0 name eth0.5 type vlan id 5
ip -d link show eth0.5

3)设置VLAN QOS
i=0
while [ $i -le 7 ]; do
    ip link set dev eth0.5 type vlan \
        egress-qos-map $i:0
    # ip link set eth0.5 type vlan egress $i:0
    i=$((i + 1))
done
其中$i表示skb_priority,0表示vlan_qos,vlan_qos对应到VLAN以太网帧中的3bit PCP。因为PCP的值越大优先级越高,由于AVB PCP的值为2(Class B,2B,250us)和3(Class A,3A,125us),所以将普通应用程序的PCP值都设置为0后,就低于AVB流的优先级了。

4)分配IP并启动
ip addr add 192.168.5.200/24 brd 192.168.5.255 \
dev eth0.5
ip link set dev eth0.5 up
或者
ifconfig eth0.5 192.168.5.200/24 up

5)设置iptables fwmark
ip rule add fwmark 0x66 priority 9998 table 200
ip route add 192.168.5.0/24 via 192.168.5.1 \
dev eth0.5 table 200
ip route flush cache

# -j means jump, u0_a50 = 10050
# net/netfilter/xt_owner.c
# external/iptables/extensions/libxt_owner.c
iptables -t mangle -A OUTPUT -m owner \
--uid-owner u0_a50 -j MARK --set-mark 0x66
echo 0x66 > \
/proc/sys/net/ipv4/conf/eth0.5/rp_filter

# delete this fwmark
# iptables -t mangle -D OUTPUT -m owner \
--uid-owner u0_a50 -j MARK --set-mark 0x66
# echo 0 > \
/proc/sys/net/ipv4/conf/eth0.5/rp_filter

# merge ip rule and iptables to one
# ip rule add uidrange 10050-10050 priority 9998 table 200
# ip rule del uidrange 10050-10050 priority 9998 table 200

6)查看是否生效
CONFIG_NETFILTER_NETLINK_LOG=m
CONFIG_NETFILTER_XT_TARGET_LOG=m

iptables -A PREROUTING -t raw -i eth0 \
-j TRACE
iptables -A OUTPUT -t raw -o eth0 \
-j TRACE
echo "nf_log_ipv4" > \
/proc/sys/net/netfilter/nf_log/2

dmesg | grep TRACE

6 Abbreviations
fwmark:firewall mark
ojluni:Android libcore中的模块,包含OpenJDK、Language、Util、Net、IO
svc:Supervisor Call

你可能感兴趣的:(Network,Android,UID,dumpsys,ip,rule,netId)