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

读取/etc/hosts文件时Android频繁崩溃问题求助

解决Android下读取/etc/hosts导致的崩溃问题

嘿,看来你在通过C++调用Java代码读取/etc/hosts时遇到了频繁崩溃的麻烦,我来帮你梳理下可能的原因和解决办法:

1. 先解决最明显的问题:资源泄漏

你的Java代码里没有关闭BufferedReader和相关输入流,多次调用后会耗尽系统的文件描述符,最终导致崩溃。这是最常见的诱因,先把这个修复了:

方案A:使用Java 7+的try-with-resources(推荐)

这种方式会自动帮你关闭资源,不需要手动写finally:

public boolean IsAdBlocked() {
    try (BufferedReader in = new BufferedReader(
            new InputStreamReader(new FileInputStream("/etc/hosts")))) {
        String aLine;
        while ((aLine = in.readLine()) != null) {
            if (aLine.contains("admob")) {
                return true;
            }
        }
    } catch (IOException e) {
        e.printStackTrace(); // 至少记录异常,方便后续排查问题
    }
    return false;
}

方案B:手动在finally块关闭资源

如果你的项目还在使用Java 6及以下版本,就用这种方式:

public boolean IsAdBlocked() {
    BufferedReader in = null;
    try {
        in = new BufferedReader(new InputStreamReader(new FileInputStream("/etc/hosts")));
        String aLine;
        while ((aLine = in.readLine()) != null) {
            if (aLine.contains("admob")) {
                return true;
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (in != null) {
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    return false;
}

2. 确认hosts文件的路径与访问权限

有些Android设备的hosts文件实际路径可能是/system/etc/hosts(/etc通常是它的软链接,但某些定制ROM可能有差异),而且虽然全局可读,但偶尔会遇到权限限制。可以同时检查两个路径,确保能读到正确的文件:

private static final String[] HOSTS_PATHS = {"/etc/hosts", "/system/etc/hosts"};

public boolean IsAdBlocked() {
    for (String path : HOSTS_PATHS) {
        File hostsFile = new File(path);
        if (!hostsFile.exists() || !hostsFile.canRead()) {
            continue;
        }
        try (BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(hostsFile)))) {
            String aLine;
            while ((aLine = in.readLine()) != null) {
                if (aLine.contains("admob")) {
                    return true;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    return false;
}

3. 检查JNI调用的正确性

C++调用Java代码时,线程管理和引用处理不当也会导致崩溃:

  • 线程附着/分离:如果在非Java线程中调用JNI方法,需要先附着到JVM,调用完成后再分离:
    JNIEnv* env;
    int attachResult = g_jvm->AttachCurrentThread(&env, nullptr);
    if (attachResult != JNI_OK) {
        // 处理附着失败的情况
        return false;
    }
    
    // 缓存类和方法ID(不要每次调用都重新查找,影响性能还容易出错)
    static jclass adCheckerClass = nullptr;
    static jmethodID isAdBlockedMethod = nullptr;
    if (adCheckerClass == nullptr) {
        adCheckerClass = static_cast<jclass>(env->NewGlobalRef(env->FindClass("com/your/package/YourAdCheckerClass")));
        isAdBlockedMethod = env->GetMethodID(adCheckerClass, "IsAdBlocked", "()Z");
    }
    
    jboolean isBlocked = env->CallBooleanMethod(yourJavaObjectInstance, isAdBlockedMethod);
    
    // 检查并清除JNI异常,避免异常传播导致崩溃
    if (env->ExceptionCheck()) {
        env->ExceptionClear();
        isBlocked = JNI_FALSE;
    }
    
    g_jvm->DetachCurrentThread();
    return isBlocked;
    
  • 缓存类和方法ID:每次调用都查找类和方法ID不仅慢,还可能引发意外错误,建议缓存为全局引用。

4. 考虑更可靠的替代方案

读取hosts文件的方式并不完美,因为有些广告屏蔽工具不用修改hosts。你可以尝试通过加载测试广告来间接判断:

  • 加载一个AdMob测试广告,监听加载回调,如果多次加载失败(排除网络问题),则认为广告被屏蔽。这种方式不需要读取系统文件,避开了权限和路径的坑,也更准确。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 10:21:30