Android NDK执行.so文件返回退出码0但无执行效果如何解决
问题根因
- 常规CMake编译生成的Android
.so是动态链接库,仅用于dlopen加载调用,默认没有可执行程序的加载头与入口配置,哪怕你实现了main函数也无法被exec系统调用直接加载执行。你看到的进程返回码0实际是加载失败直接退出的状态,main函数完全没有被调用,所以没有日志和文件输出。 - 你的执行代码存在路径缺失问题:直接写
exec mylib.so时,su的执行环境没有对应的库路径搜索配置,系统找不到对应文件,也会导致执行失败。
修复步骤
1. 修正编译配置
如果你需要以独立进程的方式执行逻辑,不要用add_library编译动态库,改为编译可执行PIE程序(Android 5.0+要求可执行文件必须是位置无关的PIE格式),CMake配置修改如下:
add_executable(mylib_exec your_source_file.c) set_target_properties(mylib_exec PROPERTIES POSITION_INDEPENDENT_CODE ON LINK_FLAGS "-pie -rdynamic" # 若需要保留.so后缀可以加下面这行 OUTPUT_NAME "mylib" SUFFIX ".so" ) find_library( log-lib log ) target_link_libraries( mylib_exec ${log-lib} )
如果你需要保留动态库供应用内加载,同时支持直接执行,也可以保留原来的add_library配置,新增上面的add_executable配置生成两个产物即可。
2. 修正执行逻辑
首先把编译出的可执行文件推送到设备的可执行目录,赋予可执行权限:
adb push mylib.so /data/local/tmp/ adb shell chmod 755 /data/local/tmp/mylib.so
修改Java层的执行代码,补全绝对路径:
process = new ProcessBuilder(new String[]{"su", "-c", "exec /data/local/tmp/mylib.so"}).start();
3. 日志获取
- 本地文件日志:执行完成后,需要用su权限读取
/data/local/tmp/log.txt,该文件是root身份生成,普通应用默认没有读取权限。 - Logcat日志:需要在C代码开头定义LOG_TAG才能正常过滤日志:
执行后用adb命令过滤日志即可:#define LOG_TAG "MY_LIB_TEST" #include <android/log.h>adb logcat -s MY_LIB_TEST:*
4. 手动调试排查
你可以先在adb shell中手动执行命令,直接看报错信息:
adb shell su cd /data/local/tmp ./mylib.so
如果是依赖库缺失、权限不足、格式错误等问题,会直接在终端输出报错,方便快速定位。
可选方案:应用内加载执行
如果你不需要开独立进程跑逻辑,可以改为常规动态库加载调用的方式,不需要su权限:
- 在原有C代码中新增JNI导出函数:
#include <jni.h> JNIEXPORT void JNICALL Java_com_your_package_MainActivity_runMyLogic(JNIEnv *env, jobject thiz) { // 直接调用你的原有main逻辑 main(0, NULL); }
- Java层声明native方法,调用
System.loadLibrary("mylib")加载so后直接调用该native方法即可。
内容的提问来源于stack exchange,提问作者MRDRAG
相关产品推荐
相关产品推荐

