Android中使用logwrapper来重定向应用程序中的标准输出 _linux console_android init_abdroid stdout err重定向

本文介绍了在Android环境中如何使用logwrapper命令将第三方应用程序的日志输出重定向到Android的logging系统中,使得logcat能够捕获原本通过标准输出如printf等函数产生的日志。此外,还探讨了如何在Windows环境下解决printf缓存问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

有时候第三方应用程序的日志输出是通过printf之类的标准函数输出的,logcat不能捕获到这些日志。一个技巧是使用logwrapper命令来执行第三方应用程序,logwrapper可以把标准输出重定向到adb log中去。(缺省级别是LOGI)


Usage: logwrapper [-x] BINARY [ARGS ...]

Forks and executes BINARY ARGS, redirecting stdout and stderr to
the Android logging system. Tag is set to BINARY, priority is
always LOG_INFO.

-x: Causes logwrapper to SIGSEGV when BINARY terminates
    fault address is set to the status of wait()

Source for logwrapper is at: system/core/logwrapper/logwrapper.c


例如,在adb shell下

root@android:/ ps

ps的结果只在当前控制台下输出,要想把ps的结果输出到adb log中去,可以使用:

root@android:/ logwrapper ps

这样adb logcat就能捕获到ps的输出了



linux console:

http://bbs.ednchina.com/BLOG_ARTICLE_1799023.HTM


android init:

http://blog.youkuaiyun.com/hongjiujing/article/details/6832825



源码是Flying项目(http://code.google.com/p/flying-on-android/)中的ToolIO.cpp

    这个程序主要演示了如何重定向一个程序的STDOUT和STDERR。

  Android中由系统启动的进程,默认STDOUT和STDERR是被定向到/dev/null中去的,所以,从adb shell是看不到程序的输出的,只能通过LOGW等打印,然后通过logcat查看。

  不过,从shell启动的可执行二进制程序倒是没有被重定向,STDOUT和STDERR都被定向到启动程序时的终端。可以编译运行一下ToolIO:

  ToolIO

  使用默认的STDOUT和STDERR。可以看到所有输出。

  ToolIO console

  把STDOUT和STDERR重定向到/dev/console。输出效果和重定向前一样。

  ToolIO null

  把STDOUT和STDERR重定向到/dev/null。重定向后看不到任何输出。

  这说明,通过串口从SHELL启动ToolIO时,程序的STDOUT和STDERR和ToolIO一样,都是/dev/console,所以重定向到/dev/console时,输出没有什么改变。

  Android源码中有很多printf,但这些输出在串口是看不到的, 因为这些源码编出的程序并没有通过串口启动。

  另外,Android的bionic中stderr默认是没有缓冲的,而stdout是有缓冲的。有缓冲,写到stdout中的字符会被积累起来,直到堆满缓冲区或者遇到/n才会把所有内容一次打印出来。





问个windows的问题
我在程序a有printf的语句
然后我这样调用 a>log.txt,把标准输出重定向到log.txt
现在问题是我printf之后,数据不会立刻输出到log.txt,会缓存起来直到一定的量
怎样能让printf之后,log.txt立刻能看到结果

LS的解释是正确的printf是行缓冲,只有缓冲满或换行时才刷新显示。
解决方法是在printf后加一句fflush(stdout);来手动刷新缓冲即可。

你的printf 有没有 \n 回车符。因为 printf 是行缓冲的。

<think>嗯,用户需要解决Android平台上的CFI检查失败错误。首先需要理解CFI(Control Flow Integrity)是什么。CFI是一种安全机制,用于防止攻击者通过控制流劫持来执行恶意代码。在Android中,它通过编译器在编译时插入检查指令来实现,比如LLVM的CFI。 用户遇到的错误可能有几种情况:一种是直接崩溃,日志中出现"cfi error";另一种是安全机制触发的异常。需要确定错误发生的上下文,比如发生在原生代码(C/C++)中还是ART虚拟机层面。如果是原生代码,问题可能出在函数指针调用或虚函数表被破坏。 接下来考虑常见原因。函数指针类型不匹配是一个典型问题,比如将不同签名的函数赋值给指针,导致CFI检查失败。另一个可能是编译器选项配置不当,比如在部分模块中未启用CFI,或者ABI兼容性问题。此外,第三方库如果没有正确支持CFI,也会引发错误。 解决方案方面,首先要检查日志,定位崩溃点。然后检查函数指针和虚函数的使用是否符合规范。编译器选项需要确保CFI在整个项目中一致启用,特别要注意第三方库的集成方式。对于第三方库,可能需要重新编译或联系供应商提供支持CFI的版本。 调试工具如NDK的addr2line可以帮助分析原生代码崩溃位置。Android Studio的内存调试工具也可能有用。如果问题在ART层面,可能需要检查JNI代码是否正确处理了异常,或者动态加载的代码是否合规。 最后,如果所有方法都无效,作为最后手段可以考虑在特定模块禁用CFI,但这会降低安全性,需谨慎评估风险。用户可能需要权衡安全性和稳定性,特别是在旧设备或资源受限的环境中。</think>在 Android 平台上遇到 CFI (Control Flow Integrity) 检查失败错误,通常表明应用程序的原生代码(C/C++)在执行过程中违反了控制流完整性保护机制。这通常是由编译器(如 Clang 的 `-fsanitize=cfi`)插入的安全检查触发的运行时错误。以下是排查和解决此问题的步骤: --- ### **1. 理解错误原因** CFI 旨在防止控制流劫持攻击(如 ROP/JOP),它会在间接调用(函数指针、虚函数调用)时验证目标地址是否属于预期的函数类型。失败原因主要有: * **函数指针类型不匹配**:实际调用的函数签名与指针声明的类型不符。 * **虚函数表 (vtable) 损坏**:对象生命周期管理错误(如 use-after-free)导致 vtable 指针被篡改。 * **ABI 不兼容**:混合使用不同编译选项(如异常处理、RTTI)或不同编译器生成的库。 * **第三方库未启用 CFI**:依赖的预编译库未开启 CFI 支持,导致调用时检查失败。 * **编译器/链接器问题**:CFI 元数据生成或处理错误。 --- ### **2. 定位错误源头** * **分析崩溃日志 (`logcat`)**: ```bash adb logcat | grep -E "cfi|signal|DEBUG|Abort" ``` 关键信息: * `"cfi: bad vtable"`:虚函数调用失败。 * `"cfi: invalid function type"`:函数指针调用失败。 * **崩溃堆栈**:定位到触发错误的代码位置(使用 `addr2line` 解析地址)[^1]。 * **启用详细诊断**:在 `Android.mk` 或 `CMakeLists.txt` 中添加: ```cmake target_compile_options(yourlib PRIVATE -fno-sanitize-trap=cfi -fsanitize-recover=cfi) ``` 使 CFI 错误可恢复并输出详细类型信息。 --- ### **3. 解决方案** #### **(1) 修复代码问题** * **函数指针**:确保赋值和调用时的类型严格一致: ```c // 错误示例:类型不匹配 void (*func_ptr)(int) = (void (*)(int))&string_function; // 强制转换危险! func_ptr(42); // CFI 失败 // 正确:使用匹配类型 typedef void (*StrFunc)(const char*); StrFunc ptr = &string_function; ptr("hello"); ``` * **虚函数调用**: * 检查对象是否已释放(use-after-free)。 * 确保父类析构函数为 `virtual`。 * 避免跨共享库继承(不同库的 vtable 布局可能不同)。 #### **(2) 统一编译选项** * **启用 CFI 贯穿所有模块**:在 `CMakeLists.txt` 中全局设置: ```cmake set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=cfi -flto -fvisibility=default") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=cfi -flto -fvisibility=default") ``` * **第三方库处理**: * 重新编译源码并启用相同 CFI 选项。 * 若无源码,在调用处禁用局部 CFI: ```c __attribute__((no_sanitize("cfi"))) void call_unsafe_library_function() { ... } ``` * 使用官方提供的支持 CFI 的预编译库。 #### **(3) 检查 ABI 兼容性** * 确保所有库使用相同的: * C++ 标准(如 `-std=c++17`)。 * 异常处理开关(`-fexceptions` / `-fno-exceptions`)。 * RTTI 开关(`-frtti` / `-fno-rtti`)。 #### **(4) 调试工具** * **LLVM `cfi-verbose` 标志**:在运行时输出详细诊断信息: ```bash adb shell setprop wrap.<app_package> '"LIBC_DEBUG_MALLOC_OPTIONS=backtrace logwrapper"' ``` * **Android Studio Memory Profiler**:检测内存损坏(如堆溢出)。 * **NDK `ndk-stack`**:解析原生崩溃堆栈: ```bash adb logcat | ndk-stack -sym ./obj/local/armeabi-v7a ``` #### **(5) 降级方案(最后手段)** 在特定源文件禁用 CFI: ```c // 文件顶部禁用 __attribute__((no_sanitize("cfi"))) void risky_function() { ... } ``` > **警告**:这会削弱安全防护,仅临时使用[^2]。 --- ### **4. 验证修复** 1. 使用 **Release 模式** 重新编译(CFI 在 Debug 模式可能被禁用)。 2. 在 **支持 CFI 的设备**(Android 8.0+)上测试。 3. 运行高覆盖率测试用例,确保无新增崩溃。 --- ### **相关问题** 1. 如何为 Android NDK 项目正确启用 CFI 防护? 2. Android 原生代码崩溃分析有哪些高级工具? 3. 如何避免 JNI 开发中的常见内存错误? 4. LLVM Sanitizers (ASAN, UBSAN) 在 Android 中如何集成? [^1]: CFI 错误日志会包含崩溃地址,使用 `addr2line -e <your_lib.so> <address>` 定位代码行。 [^2]: 降级方案仅适用于无法修改的闭源库,自身代码应优先修复类型问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值