android JNI(1)- gelf_update_phdr(): invalid data

本文介绍了一次JNI动态库构建过程中遇到的瘦身错误及解决方法。通过调整第三方库的编译器版本,成功解决了在Android平台上的编译问题。

关于JNI的基本使用方法,网络上有很多文章。我只想把我最近遇到的关于JNI的问题总结一下。

 

在android 源码下创建一个工程,将源文件拷贝到工程目录的 apps和jni文件夹下。

工程的Android.mk文件为

LOCAL_PATH := $(call my-dir)
LIB_COMMC_INCLUDE := $(LOCAL_PATH)/../../bionic/libc/include
include $(CLEAR_VARS)

LOCAL_SRC_FILES:=/
./apps/bdk_app_demo.c/
./apps/bdk_app_generic.c/
./apps/bdk_app_spp_c.c/
./apps/bdk_app_spp_drv.c/
./apps/bdk_app_spp_s.c/
./apps/bdk_app_sys.c/
./apps/iconv.c/
./apps/bdk_app_ui_data.c/
./apps/cheat_fun.c/
./jni/jnimain.c

LOCAL_C_INCLUDES:=/
    $(JNI_H_INCLUDE)/
    $(LOCAL_PATH)/inc/
    $(LOCAL_PATH)/apps/
    $(LIB_COMMC_INCLUDE)

LOCAL_STATIC_LIBRARIES:=/

libcutils

LOCAL_LDFLAGS+=

       $(LOCAL_PATH)/lib/libgeneric.a/
        $(LOCAL_PATH)/lib/libstack.a/
        $(LOCAL_PATH)/lib/libsys.a/
        $(LOCAL_PATH)/lib/libusb.a

LOCAL_PRELINK_MODULE:=false
LOCAL_MODULE:=libhello

include $(BUILD_SHARED_LIBRARY)

 

工程源文件如LOCAL_SRC_FILES所示,除了libc库外,还包括了四个外部链接库libgeneric.a libstack.a libsys.a libusb.a, 这四个库为第三方得到,而且已经被证明在android平台上可用的。

模块名由LOCAL_MODULE=libhello指定,include $(BUILD_SHARED_LIBRARY)表示目标模块被编译为动态库,JNI要求Native代码编译为动态库供虚拟机加载。

 

配置好工程的源文件和Android.mk后,执行make libhello SHOW_COMMANDS=a; 经过分析android的build系统,我发现只要将SHOW_COMMANDS设置为一个非空的字符串,就可以在make 的过程中将Makefile命令执行的内容打印。虽然android build系统提供了一个showcommands命令来完成同样的工作,我习惯了用前面的方式。

 

最初的build出现了一个错误,build log显示为:

target non-prelinked: libhello (out/target/product/generic/symbols/system/lib/libhello.so)
out/host/linux-x86/bin/acp -fpt
out/target/product/generic/obj/SHARED_LIBRARIES/libhello_intermediates/LINKED/libhello.so
out/target/product/generic/symbols/system/lib/libhello.so
target Strip: libhello (out/target/product/generic/obj/lib/libhello.so)
out/host/linux-x86/bin/soslim --strip --shady --quiet
out/target/product/generic/symbols/system/lib/libhello.so --outfile
out/target/product/generic/obj/lib/libhello.so
external/elfcopy/elfcopy.c(1097): gelf_update_phdr(): invalid data
make: *** [out/target/product/generic/obj/lib/libhello.so] Error 1
make: *** Deleting file `out/target/product/generic/obj/lib/libhello.so'

 

错误行为external/elfcopy/elfcopy.c(1097): gelf_update_phdr(): invalid data

 

从源代码结构以及上面的 Log可以看到,elfcopy是 soslim模块的一部分, soslim是源代码目录toolchain工具arm-eabi-strip的替代工具,功能是为了去除库中多余的符号和调试信息,为动态库瘦身。

 

通过分析make输出的日志。动态库的生成包括几个过程:

1 设置目标和主机相关的变量(包括编译器选择,基本编译选项设置以及其他build变量设置)

2 读取所有模块的Android.mk,生成各模块的build规则。

3 执行libhello的build过程

   编译源文件

   连接目标文件为动态库

   使用soslim为动态库瘦身

   将瘦身的libhello 复制到输出文件夹

 

当前的错误出现在步骤3的瘦身过程。好在android Developer的mail list中,看到有帖子遇到了同样的问题,在发言中有人建议使用gcc 4.2.4以下版本生成目标文件。 android build system默认使用gcc 4.2.1版本编译器。最后发现那四个第三方库使用的是gcc 4.3.1编译器生成, 重编那四个lib库, 问题解决了。

*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 2025-10-16 16:01:44.327 21278-21278 DEBUG crash_dump64 A Build fingerprint: 'realme/RMX3561EEA/RED8BEL1:12/SP1A.210812.016/S.GDPR.202204240300:user/release-keys' 2025-10-16 16:01:44.327 21278-21278 DEBUG crash_dump64 A Revision: '0' 2025-10-16 16:01:44.327 21278-21278 DEBUG crash_dump64 A ABI: 'arm64' 2025-10-16 16:01:44.327 21278-21278 DEBUG crash_dump64 A Timestamp: 2025-10-16 16:01:44.027747034+0800 2025-10-16 16:01:44.327 21278-21278 DEBUG crash_dump64 A Process uptime: 0s 2025-10-16 16:01:44.327 21278-21278 DEBUG crash_dump64 A Cmdline: com.tplink.vigi 2025-10-16 16:01:44.327 21278-21278 DEBUG crash_dump64 A pid: 21112, tid: 21163, name: executor >>> com.tplink.vigi <<< 2025-10-16 16:01:44.327 21278-21278 DEBUG crash_dump64 A uid: 10502 2025-10-16 16:01:44.327 21278-21278 DEBUG crash_dump64 A tagged_addr_ctrl: 0000000000000001 2025-10-16 16:01:44.327 21278-21278 DEBUG crash_dump64 A signal 6 (SIGABRT), code -1 (SI_QUEUE), fault addr -------- 2025-10-16 16:01:44.327 21278-21278 DEBUG crash_dump64 A Abort message: 'terminating with uncaught exception of type std::invalid_argument: stoi: no conversion' 2025-10-16 16:01:44.327 21278-21278 DEBUG crash_dump64 A x0 0000000000000000 x1 00000000000052ab x2 0000000000000006 x3 000000749cdc00d0 2025-10-16 16:01:44.327 21278-21278 DEBUG crash_dump64 A x4 736f646277641f73 x5 736f646277641f73 x6 736f646277641f73 x7 7f7f7f7f7f7f7f7f 2025-10-16 16:01:44.327 21278-21278 DEBUG crash_dump64 A x8 00000000000000f0 x9 00000075c892a2c0 x10 ffffff00fffffbdf x11 0000000000000001 2025-10-16 16:01:44.327 21278-21278 DEBUG crash_dump64 A x12 00000075de224020 x13 000000007fffffff x14 0000000009e99640 x15 00000650bad6cd74 2025-10-16 16:01:44.327 21278-21278 DEBUG crash_dump64 A x16 00000075c89eebb0 x17 00000075c89ca450 x18 0000007494b22000 x19 00000000000000ac 2025-10-16 16:01:44.327 21278-21278 DEBUG crash_dump64 A x20 0000000000005278 x21 00000000000000b2 x22 00000000000052ab x23 00000000ffffffff 2025-10-16 16:01:44.327 21278-21278 DEBUG crash_dump64 A x24 000000749cdc0210 x25 000000749cdc0250 x26 000000749cdc2ff8 x27 00000000000fe000 2025-10-16 16:01:44.327 21278-21278 DEBUG crash_dump64 A x28 00000000000fc000 x29 000000749cdc0150 2025-10-16 16:01:44.327 21278-21278 DEBUG crash_dump64 A lr 00000075c897bb6c sp 000000749cdc00b0 pc 00000075c897bb9c pst 0000000000001000 2025-10-16 16:01:44.327 21278-21278 DEBUG crash_dump64 A backtrace: 2025-10-16 16:01:44.327 21278-21278 DEBUG crash_dump64 A #00 pc 0000000000078b9c /apex/com.android.runtime/lib64/bionic/libc.so (abort+180) (BuildId: f24f65acf653c409ca4332aced817a71) 2025-10-16 16:01:44.327 21278-21278 DEBUG crash_dump64 A #01 pc 00000000016d0aa8 /data/app/~~Yt-lNiqGfFqvCdh8YsZhlQ==/com.tplink.vigi-aX1-T_7psBjaBsIw3FG3xg==/base.apk!libIPCAppContextJNI.so (BuildId: 0f65dbc031b0a5abe91b4498331668eb5c91f764) 2025-10-16 16:01:44.327 21278-21278 DEBUG crash_dump64 A #02 pc 00000000016d0cd0 /data/app/~~Yt-lNiqGfFqvCdh8YsZhlQ==/com.tplink.vigi-aX1-T_7psBjaBsIw3FG3xg==/base.apk!libIPCAppContextJNI.so (BuildId: 0f65dbc031b0a5abe91b4498331668eb5c91f764) 2025-10-16 16:01:44.328 21278-21278 DEBUG crash_dump64 A #03 pc 00000000016d0b60 /data/app/~~Yt-lNiqGfFqvCdh8YsZhlQ==/com.tplink.vigi-aX1-T_7psBjaBsIw3FG3xg==/base.apk!libIPCAppContextJNI.so (BuildId: 0f65dbc031b0a5abe91b4498331668eb5c91f764) 2025-10-16 16:01:44.328 21278-21278 DEBUG crash_dump64 A #04 pc 00000000016d0100 /data/app/~~Yt-lNiqGfFqvCdh8YsZhlQ==/com.tplink.vigi-aX1-T_7psBjaBsIw3FG3xg==/base.apk!libIPCAppContextJNI.so (BuildId: 0f65dbc031b0a5abe91b4498331668eb5c91f764) 2025-10-16 16:01:44.328 21278-21278 DEBUG crash_dump64 A #05 pc 00000000016d0058 /data/app/~~Yt-lNiqGfFqvCdh8YsZhlQ==/com.tplink.vigi-aX1-T_7psBjaBsIw3FG3xg==/base.apk!libIPCAppContextJNI.so (__cxa_throw+124) (BuildId: 0f65dbc031b0a5abe91b4498331668eb5c91f764) 2025-10-16 16:01:44.328 21278-21278 DEBUG crash_dump64 A #06 pc 00000000016c9bfc /data/app/~~Yt-lNiqGfFqvCdh8YsZhlQ==/com.tplink.vigi-aX1-T_7psBjaBsIw3FG3xg==/base.apk!libIPCAppContextJNI.so (std::__ndk1::stoi(std::__ndk1::basic_string<char, std::__ndk1::char_traits<char>, std::__ndk1::allocator<char> > const&, unsigned long*, int)+392) (BuildId: 0f65dbc031b0a5abe91b4498331668eb5c91f764) 2025-10-16 16:01:44.328 21278-21278 DEBUG crash_dump64 A #07 pc 0000000000fc9104 /data/app/~~Yt-lNiqGfFqvCdh8YsZhlQ==/com.tplink.vigi-aX1-T_7psBjaBsIw3FG3xg==/base.apk!libIPCAppContextJNI.so (TPWCOMMHLIPC::OnGetModuleSpec(int, TPWIPCDeviceModuleSpec*, char const*, int, int)+4232) (BuildId: 0f65dbc031b0a5abe91b4498331668eb5c91f764) 2025-10-16 16:01:44.328 21278-21278 DEBUG crash_dump64 A #08 pc 0000000000e541c4 /data/app/~~Yt-lNiqGfFqvCdh8YsZhlQ==/com.tplink.vigi-aX1-T_7psBjaBsIw3FG3xg==/base.apk!libIPCAppContextJNI.so (IPCDevConnectTaskNew::OnTaskGetResponse(int)+2208) (BuildId: 0f65dbc031b0a5abe91b4498331668eb5c91f764) 2025-10-16 16:01:44.328 21278-21278 DEBUG crash_dump64 A #09 pc 0000000000c39cc4 /data/app/~~Yt-lNiqGfFqvCdh8YsZhlQ==/com.tplink.vigi-aX1-T_7psBjaBsIw3FG3xg==/base.apk!libIPCAppContextJNI.so (IPCSimpleBaseExecutorTask::Execute()+1612) (BuildId: 0f65dbc031b0a5abe91b4498331668eb5c91f764) 2025-10-16 16:01:44.328 21278-21278 DEBUG crash_dump64 A #10 pc 00000000011f7858 /data/app/~~Yt-lNiqGfFqvCdh8YsZhlQ==/com.tplink.vigi-aX1-T_7psBjaBsIw3FG3xg==/base.apk!libIPCAppContextJNI.so (TPEXECUTORTHREAD::ThreadFunc(void*)+276) (BuildId: 0f65dbc031b0a5abe91b4498331668eb5c91f764) 2025-10-16 16:01:44.328 21278-21278 DEBUG crash_dump64 A #11 pc 0000000000f5ad84 /data/app/~~Yt-lNiqGfFqvCdh8YsZhlQ==/com.tplink.vigi-aX1-T_7psBjaBsIw3FG3xg==/base.apk!libIPCAppContextJNI.so (ThreadFun+56) (BuildId: 0f65dbc031b0a5abe91b4498331668eb5c91f764) 2025-10-16 16:01:44.328 21278-21278 DEBUG crash_dump64 A #12 pc 00000000000dc188 /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+264) (BuildId: f24f65acf653c409ca4332aced817a71) 2025-10-16 16:01:44.328 21278-21278 DEBUG crash_dump64 A #13 pc 000000000007a438 /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+64) (BuildId: f24f65acf653c409ca4332aced817a71)
最新发布
10-17
<think>我们正在处理一个Android应用崩溃的问题,具体异常是`std::invalid_argument: stoi: no conversion`。这个异常通常发生在尝试将字符串转换为整数时,字符串的格式不符合整数格式要求(比如包含非数字字符、空字符串等)。 根据用户提到的应用名称`com.tplink.vigi`,这可能是TP-Link的Vigi应用(可能是智能摄像头或安防相关应用)。异常发生在C++层(因为使用了`std::stoi`),所以可能是JNI代码中出现了问题。 ### 步骤分析 1. **理解异常原因**: - `std::stoi`在转换无效字符串时会抛出`std::invalid_argument`异常。例如: - 字符串为空 - 字符串包含非数字字符(除了开头可能允许的负号) - 例如:`std::stoi("123")`成功,但`std::stoi("abc")`会抛出异常。 2. **定位问题代码**: - 由于异常发生在C++层,我们需要检查应用中的JNI代码(即C/C++代码)中所有使用`std::stoi`(或类似函数,如`stol`, `stoll`)的地方。 - 需要检查传入这些函数的字符串是否可能包含非数字内容。 3. **解决方案**: - 在调用`std::stoi`之前,先验证字符串是否是一个有效的整数表示。 - 或者使用异常处理(try-catch)来捕获异常,避免崩溃。 ### 具体解决步骤 #### 1. 验证字符串 在调用`std::stoi`之前,先检查字符串是否由数字组成(或者允许的负号)。例如: ```cpp #include <cctype> #include <string> bool isInteger(const std::string &s) { if (s.empty()) return false; int start = 0; if (s[0] == '-') { // 处理负号 if (s.size() == 1) return false; // 只有负号不行 start = 1; } for (int i = start; i < s.length(); i++) { if (!std::isdigit(static_cast<unsigned char>(s[i]))) { return false; } } return true; } // 使用示例 std::string numStr = ...; if (isInteger(numStr)) { int num = std::stoi(numStr); } else { // 处理无效情况,例如给默认值或记录错误 } ``` #### 2. 使用异常处理 如果不想预先检查,可以使用try-catch块: ```cpp try { int num = std::stoi(numStr); } catch (const std::invalid_argument& e) { // 处理转换失败的情况 // 例如:记录日志,设置默认值等 } catch (const std::out_of_range& e) { // 处理超出范围的情况 } ``` ### 在Android项目中定位问题 由于异常发生在C++代码中,我们需要在Android项目中查找JNI代码(通常位于`app/src/main/cpp`或`app/src/main/jni`目录)。可以搜索`stoi`的调用点,然后按照上述方法进行修改。 ### 注意事项 - 确保传入`std::stoi`的字符串不为空,且格式正确。 - 如果字符串来自Java层(通过JNI传递),确保在Java层进行校验,或者在C++层进行校验。 - 如果字符串来自网络或文件,需要特别注意数据源的可靠性,并进行严格的校验。 ### 示例修改 假设我们找到一处有问题的代码: 原始代码: ```cpp std::string str = ...; // 可能不是有效的整数 int value = std::stoi(str); ``` 修改后: ```cpp std::string str = ...; try { int value = std::stoi(str); // 使用value } catch (const std::invalid_argument& e) { // 记录错误并使用默认值 int value = 0; } ``` 或者使用预检查函数(推荐,避免异常开销): ```cpp std::string str = ...; if (isInteger(str)) { int value = std::stoi(str); } else { // 处理错误 } ``` ### 总结 解决`std::invalid_argument: stoi: no conversion`异常的关键在于确保传递给`stoi`的字符串是有效的整数格式。通过预先校验或异常处理,可以避免应用崩溃。 §§相关问题§§ 1. 如何在Android JNI中捕获C++异常? 2. 除了`std::stoi`,还有哪些字符串转整数的安全方法? 3. 如何调试Android应用的Native崩溃? </think>### 解决 `com.tplink.vigi` 应用崩溃:`std::invalid_argument: stoi: no conversion` 异常的方法 该异常表明应用在尝试将字符串转换为整数时失败(通常发生在 C++ 代码中)。以下是系统性的解决步骤: --- #### 1. **定位问题根源** - **异常触发点**:`std::stoi()` 函数尝试转换非数字字符串(如空字符、字母、"123abc" 等)。 - **常见场景**: - 解析 JSON/XML 数据时字段值异常(如 `"value": "N/A"`)。 - 从网络请求或本地存储读取的数据格式错误。 - JNI(Java Native Interface)层数据传递错误。 --- #### 2. **检查数据来源(优先排查项)** - **网络请求数据**: 检查 API 返回字段(如设备状态值、配置参数)。例如: ```json // 错误示例:预期数字但返回字符串 {"brightness": "auto"} // 应为数值如 {"brightness": 50} ``` **解决方案**: 在解析前添加类型校验逻辑(示例代码): ```java // Java 层校验(Kotlin 同理) String value = json.optString("brightness", "0"); // 默认值防崩溃 if (value.matches("\\d+")) { // 正则校验是否为纯数字 int brightness = Integer.parseInt(value); } else { Log.e("VIGI", "Invalid number format: " + value); } ``` - **本地存储/数据库**: 检查 SQLite 或 SharedPreferences 中存储的数值字段是否被意外修改为字符串。 --- #### 3. **检查 JNI 层代码** - **JNI 数据传递**: 如果异常发生在 Native 代码(`.cpp` 文件),检查 Java 传递给 C++ 的字符串: ```cpp // 示例:JNI 函数 JNIEXPORT void JNICALL Java_com_tplink_vigi_NativeHelper_parseData(JNIEnv* env, jobject obj, jstring jData) { const char* cData = env->GetStringUTFChars(jData, nullptr); // 错误做法:未校验直接转换 // int num = std::stoi(cData); // 正确做法:添加校验 if (cData != nullptr && std::all_of(cData, cData + strlen(cData), ::isdigit)) { int num = std::stoi(cData); } else { // 处理无效输入 } env->ReleaseStringUTFChars(jData, cData); } ``` --- #### 4. **防御性编程改进** - **替换 `std::stoi` 为安全函数**: 在 C++ 代码中使用自定义安全转换函数: ```cpp #include <string> #include <exception> int safe_stoi(const std::string& str, int default_value = 0) { try { return std::stoi(str); } catch (const std::invalid_argument& e) { return default_value; // 返回默认值防崩溃 } } ``` - **Java/Kotlin 层拦截**: 在数据进入 Native 代码前拦截非法值: ```kotlin // Kotlin 示例 fun passToNative(value: String) { if (value.toIntOrNull() == null) { Log.w("VIGI", "Invalid integer: $value") return } NativeHelper.parseData(value) // 调用 JNI } ``` --- #### 5. **调试与日志** - **捕获崩溃堆栈**: 使用 `adb logcat` 过滤崩溃日志: ```bash adb logcat | grep -E 'com.tplink.vigi|std::invalid_argument' ``` - **关键日志点**: 在调用 `std::stoi()` 前打印待转换字符串: ```cpp __android_log_print(ANDROID_LOG_ERROR, "VIGI", "Converting: %s", cData); ``` --- #### 6. **验证第三方 SDK** 如果异常发生在 TP-Link 提供的 SDK 中: - 更新至最新 SDK 版本(可能已修复问题)。 - 联系 TP-Link 技术支持,提供完整的崩溃堆栈和复现步骤。 --- ### 总结步骤 ```mermaid graph TD A[崩溃发生] --> B{检查数据来源} B --> C[网络请求数据] B --> D[本地存储/数据库] B --> E[JNI 层传递] C --> F[添加类型校验] D --> G[修正数据格式] E --> H[加固 Native 转换逻辑] F --> I[回归测试] G --> I H --> I I --> J[问题解决] ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值