读取/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
相关产品推荐
相关产品推荐

