You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android应用实现traceroute功能的方案选型与问题排查

Android端实现Traceroute功能问题解答

问题背景

我是Android应用开发领域的新手,也是Stack Overflow新用户。由于Android设备默认未预装traceroute工具,我尝试在自研Android应用中复刻Linux traceroute功能,参考多个Stack Overflow帖子方案后仍遇到若干问题,开发环境为Android Studio 3.3.0,应用最低支持SDK版本为API 21。

已尝试方案及现存问题

  • 基于ping的实现方案
    参考Stack Overflow帖子《Traceroute on android》的示例项目逻辑:持续向目标IP发送ping请求,逐次递增TTL(生存时间)字段值获取中间路由器信息。复现时特定TTL值下ping会阻塞挂起,无法返回路由器信息,测试代码如下,循环执行到某一TTL值时进程就会停滞:
    public static void smallTracerouteDemoShowingThatTheProgramStallsAtCertainTTLs() {
        try {
            String host = "google.com";
            int maxTTL = 20;
    
            for (int i = 1; i < maxTTL; i++) {
                // 创建执行ping命令的进程
                Process p = Runtime.getRuntime().exec("ping -c 1 -t " + i + " " + host);
    
                // 获取ping返回信息的输入流读取器
                BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
    
                // 读取所有返回内容
                String dataReturnedByPing = "";
                for (String line; (line = br.readLine()) != null; dataReturnedByPing += "\n"+line);
    
                // 打印当前TTL的探测结果
                System.out.println("TTL = " + i + " out of " + maxTTL);
                System.out.println(dataReturnedByPing);
                System.out.println("========================================");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
  • 基于BusyBox的实现方案
    参考Stack Overflow帖子《how to run traceroute command through your application?》的建议,需要将BusyBox嵌入应用才能运行traceroute。经调研,BusyBox单文件集成了上百个Linux命令,但我仅需要traceroute功能,且单份BusyBox二进制文件无法覆盖Android支持的所有CPU架构,因此暂不考虑该方案。
  • 基于NDK编译原生traceroute的方案
    参考GitHub上的traceroute-for-android项目思路,将traceroute源码嵌入项目,通过NDK和应用其余代码共同编译,该方案原生逻辑一致性最高,最符合需求。但导入项目实验时构建失败,顶层报错信息为:
    org.gradle.initialization.ReportedException: org.gradle.internal.exceptions.LocationAwareException: A problem occurred configuring root project 'traceroute-for-android-master'.
    

待解答问题

  1. ping实现方案中特定TTL值下ping阻塞的原因
  2. 上述NDK项目构建失败的排查方法
  3. Android平台实现traceroute功能的最优方案,尤其是适配Android Studio 3.3.0、API 21的NDK实现搭建指南

问题解答

1. ping方案特定TTL下阻塞的原因

阻塞核心是两个问题叠加:

  • 你只读取了进程的标准输出流(getInputStream()),没有读取标准错误流(getErrorStream())。当TTL到期时,中间路由器返回的ICMP超时信息在很多厂商的Android系统上会输出到标准错误流,缓冲区写满后进程就会挂起等待流被读取,造成阻塞。
  • 没有给ping命令加超时参数。部分节点会直接丢弃ICMP超时报文,没有响应的情况下ping命令会默认等待10秒以上才会超时返回,你代码里没有设置-W(超时时间,单位秒)参数,就会卡在无响应的节点上。

修复方法如下:单独开线程读取错误流,同时给ping命令加上超时参数,示例修改:

// 执行ping时增加-W 2参数,代表2秒无响应就超时
Process p = Runtime.getRuntime().exec("ping -c 1 -W 2 -t " + i + " " + host);
// 启动子线程读取错误流,避免缓冲区占满阻塞
new Thread(() -> {
    try {
        BufferedReader errBr = new BufferedReader(new InputStreamReader(p.getErrorStream()));
        while (errBr.readLine() != null) {}
    } catch (Exception ignored) {}
}).start();

另外注意Android不同版本的ping命令参数有差异,部分老版本系统-t参数的TTL设置需要放在目标地址前面,你当前写法适配API21没有问题。

2. NDK项目构建失败排查方法

你拿到的开源项目版本较老,和当前Android Studio 3.3.0、API21的环境不匹配,按以下顺序排查即可:

  • 先修复Gradle版本不匹配问题:老项目一般使用旧版Gradle插件,打开项目根目录的build.gradle,把classpath里的Gradle插件版本改成和AS 3.3.0匹配的3.3.0版本,同时打开gradle/wrapper/gradle-wrapper.properties,把distributionUrl里的Gradle版本改成4.10.1(AS3.3.0对应支持的Gradle版本)。
  • 再检查NDK配置问题:老项目用的是旧版NDK构建逻辑,先在SDK Manager里安装对应版本的NDK(推荐NDK r19c,对API21兼容性最好),然后在项目根目录的local.properties里加上ndk.dir=你的NDK安装路径配置。如果项目用的是ndk-build旧语法,不需要迁移到CMake,直接在app模块的build.gradle里加上ndk配置,指定编译的ABI架构:
    android {
        defaultConfig {
            ndk {
                abiFilters 'armeabi-v7a','arm64-v8a','x86','x86_64'
            }
        }
    }
    
  • 最后检查SDK版本配置:把app模块build.gradle里的compileSdkVersion、minSdkVersion改成你当前使用的版本,minSdkVersion设为21即可,compileSdkVersion建议用28(和AS3.3.0兼容性最好)。

3. Android平台Traceroute最优实现方案(适配AS3.3.0+API21)

优先选择NDK编译原生traceroute的方案,比ping方案准确率高,比BusyBox方案体积小、架构覆盖全,搭建步骤如下:

  1. 新建支持NDK的Android项目,选择API21作为最低SDK版本,在SDK Manager中安装NDK r19c、CMake 3.10.2(AS3.3.0支持的稳定版本)。
  2. 下载标准Linux traceroute的核心源码(仅需traceroute.c、as.c、ifaddrlist.c等无额外依赖的C文件),放到app模块的src/main/cpp目录下。
  3. 在cpp目录下编写CMakeLists.txt,配置编译规则:
cmake_minimum_required(VERSION 3.4.1)
add_library(traceroute SHARED
        traceroute.c
        as.c
        ifaddrlist.c
        addsock.c
        cksum.c
        dnet.c
        # 列出所有用到的C文件
        )
find_library(log-lib log)
target_link_libraries(traceroute ${log-lib})
  1. 在app模块的build.gradle里配置CMake编译路径:
android {
    externalNativeBuild {
        cmake {
            path "src/main/cpp/CMakeLists.txt"
        }
    }
    defaultConfig {
        ndk {
            abiFilters 'armeabi-v7a','arm64-v8a','x86','x86_64'
        }
    }
}
  1. 编写JNI接口,调用原生traceroute逻辑,把探测结果回调到Java层即可。编译出来的so库总大小不到200KB,比嵌入BusyBox小一个数量级,支持全主流CPU架构,不需要root权限,准确率和Linux原生traceroute完全一致。

如果不想自己编写JNI逻辑,可以直接提取之前找到的开源项目里的C/C++源码和JNI接口代码,替换掉项目里的Gradle配置即可正常编译运行,不需要导入整个旧项目。


内容的提问来源于stack exchange,提问作者Amaar Ebrahim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 13:33:21