定位 Android API 30 时无法绑定 () netlink 套接字

Cannot bind() netlink socket when targeting Android API 30

我已经使用以下工具创建网络link套接字已有一段时间了:

NetLinkLocalNetworkInfo::NetLinkSocket::NetLinkSocket() :
fd(0)
{
    fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
    if(fd < 0)
    {
        throw std::runtime_error("Failed to create NetLink socket");
    }

    struct sockaddr_nl addr;
    memset(&addr, 0, sizeof(addr));
    addr.nl_family = AF_NETLINK;

    int err = bind(fd, (struct sockaddr*)&addr, sizeof(addr));
    if(err < 0)
    {
        close(fd);
        throw std::runtime_error("Failed to bind NetLink socket");
    }
}

这用于我们现有的部分网络逻辑,以使用 ICE 执行自动 NAT 遍历。当目标 API 30 时,对 bind 的调用现在 returns -1 和 errno 是“权限被拒绝”。

针对 API 30 的应用的行为变化现在意味着 bind() 是一个受限调用。 (在 Google 开发者页面的某处有一个文档,但如果我能再次找到它,我会很高兴。它曾经存在 here, but that page has changed since I first came across this issue a few months ago.) Supposedly this is supposed to affect all apps targeting API 30, but I've found that only apps targeting API 30 and running on a device (physical or emulator) running Android 11 are affected. My notes from when I first encountered this also mention that article suggesting using ConnectivityManager,但这需要想出一些方法来通过信息到本机代码或让本机代码通过 JNI 调用 Android 平台代码。如果这是必须发生的事情,我对其中任何一个都很好,但我想知道是否还有另一种选择我'我不知道。

我也看到了this similar question,但是其中一个答案中有一个link表明它应该是可能的,至少在API 30之前。

现在我们不能调用 bind(),还有哪些其他选项可用?

找到了解决办法。原来我们使用 NetLink 套接字来发现网络接口地址信息,因为 ifaddrs 在 Android 当时。截至 API 24 ifaddrs 可用。我们将实现切换为使用 ifaddrs。只要您支持的最低版本是 API 24 或更高版本,您就可以这样做。