android中打印调用栈

  1. Android中打印调用栈

包括C++/java/c

http://www.07net01.com/program/549412.html

打印堆栈是调试的常用方法,一般出现异常时,我们可以在跑出异常时也将堆栈情况打印出来,这样十分方便错误查找。另外实际上也有一个非常有用的功能:分析代码的行为。android代码太过庞大了,完全的静态分析经常是无从下手,因此通过打印堆栈的动态分析也十分必要。



Android打印堆栈的方法,简单归类一下 

1. zygote的堆栈dump

实际上这个可以同时dumpjava线程及native线程的堆栈,对于java线程,java堆栈和native堆栈都可以得到。

使用方法很简单,直接在adbshell窗口或串口中输入:

kill -3 <pid>

输出的trace会保存在/data/anr/traces.txt文件中。

如果需要在代码中,更容易控制堆栈的输出时机,可以用以下命令获取zygote的coredump:

Process.sendSignal(pid,
Process.SIGNAL_QUIT);

原理和命令行是一样的。

不过需要注意两点:

  1. adb shell可能会没有权限。

  2. android 4.2中关闭了nativethread的堆栈打印,详见dalvik/vm/Thread.cpp的dumpNativeThread方法:

    dvmPrintDebugMessage(target,
        "\"%s\" sysTid=%d nice=%d
sched=%d/%d cgrp=%s\n",
        name, tid, getpriority(PRIO_PROCESS,
tid),
        schedStats.policy, schedStats.priority,
schedStats.group);
    dumpSchedStat(target, tid);
    // Temporarily disabled collecting native
stacks from non-Dalvik
    // threads because sometimes they misbehave.
   
//dvmDumpNativeStack(target, tid);

不过对于大多数情况,可以直接将这个注释打开。

2. debuggerd的堆栈dump

debuggerd是android的一个daemon进程,负责在进程出错异常时,将进程的运行时信息给dump出来供分析。debuggerd的coredump数据,被保存在/data/tombstone/目录下(名字取的也很形象,tombstone是墓碑的意思),共可保存10个文件,当超过10个时,会覆盖重写最早生产的文件。在4.2版本中,debuggerd同时也是一个工具明了,可以在不中断进程执行的情况下打印堆栈。使用方法是:

debuggerd -b <pid>



3. java代码中打印堆栈

Java代码打印堆栈比较简单,堆栈信息获取和输出,都可以通过Throwable类的方法实现。目前通用的做法是在java进程出现需要注意的异常时,打印堆栈,然后再决定退出或挽救。通常的方法是使用exception的printStackTrace()方法:

try {
 ...
} catch (RemoteException e) {
  e.printStackTrace();
  ...
}

当然也可以只打印堆栈不退出,这样就比较方便分析代码的动态运行情况。Java代码中插入堆栈打印的方法如下:

Log.d(TAG,Log.getStackTraceString(new
Throwable()));

 

4. C++代码中打印堆栈

C++也是支持异常处理的,异常处理库中,已经包含了获取backtrace的接口,Android也是利用这个接口来打印堆栈信息的。在Android的C++中,已经集成了一个工具类CallStack,在libutils.so中。使用方法:

#include <utils/CallStack.h>
...
CallStack stack;
stack.update();
stack.dump(); 
 

使用方式比较简单。目前Andoid4.2版本已经将相关信息解析的很到位,符号表查找,demangle,偏移位置校正都做好了。

 

5. C代码中打印堆栈

C代码,尤其是底层C库,想要看到调用的堆栈信息,还是比较麻烦的。CallStack肯定是不能用,一是因为其实C++写的,需要重新封装才能在C中使用,而是底层库反调上层库的函数,会造成连接器循环依赖而无法链接。不过也不是没有办法,可以通过CallStack使用的unwind及符号函数来处理。

这里需要注意的是,为解决链接问题,最好使用dlopen方式,查找需要用到的接口再直接调用,这样会比较简单。如下为相关的实现代码,只需要在要打印的文件中插入此部分代码,然后调用getCallStack()即可,无需包含头文件和修改Android.mk文件:

#define MAX_DEPTH                       31
#define MAX_BACKTRACE_LINE_LENGTH   800
#define PATH "/system/lib/libcorkscrew.so"
 
typedef ssize_t (*unwindFn)(backtrace_frame_t*,
size_t, size_t);
typedef void (*unwindSymbFn)(const
backtrace_frame_t*, size_t, backtrace_symbol_t*);
typedef void
(*unwindSymbFreeFn)(backtrace_symbol_t*, size_t);
 
static void *gHandle = NULL;
 
static int getCallStack(void){
    ssize_t i = 0;
    ssize_t result = 0;
    ssize_t count;
    backtrace_frame_t mStack[MAX_DEPTH];
    backtrace_symbol_t symbols[MAX_DEPTH];
 
    unwindFn unwind_backtrace = NULL;
    unwindSymbFn get_backtrace_symbols = NULL;
    unwindSymbFreeFn free_backtrace_symbols =
NULL;
 
    // open the so.
    if(gHandle == NULL) gHandle = dlopen(PATH,
RTLD_NOW);
 
    // get the interface for
unwind and symbol analyse
    if(gHandle != NULL) unwind_backtrace =
(unwindFn)dlsym(gHandle, "unwind_backtrace");
    if(gHandle != NULL) get_backtrace_symbols =
(unwindSymbFn)dlsym(gHandle, "get_backtrace_symbols");
    if(gHandle != NULL) free_backtrace_symbols =
(unwindSymbFreeFn)dlsym(gHandle, "free_backtrace_symbols");
 
    if(!gHandle ||!unwind_backtrace
||!get_backtrace_symbols || !free_backtrace_symbols  ){
        ALOGE("Error! cannot get unwind
info: handle:%p %p %p %p",
            gHandle, unwind_backtrace,
get_backtrace_symbols, free_backtrace_symbols );
        return result;
    }
 
    count= unwind_backtrace(mStack, 1,
MAX_DEPTH);
    get_backtrace_symbols(mStack, count,
symbols);
 
    for
(i = 0; i < count; i++) {
        char line[MAX_BACKTRACE_LINE_LENGTH];
 
        const char* mapName =
symbols[i].map_name ? symbols[i].map_name : "<unknown>";
        const char* symbolName
=symbols[i].demangled_name ? symbols[i].demangled_name :
symbols[i].symbol_name;
        size_t fieldWidth =
(MAX_BACKTRACE_LINE_LENGTH - 80) / 2;
        
        if (symbolName) {
            uint32_t pc_offset =
symbols[i].relative_pc - symbols[i].relative_symbol_addr;
            if (pc_offset) {
                snprintf(line,
MAX_BACKTRACE_LINE_LENGTH, "#%02d  pc %08x  %.*s (%.*s+%u)",
                        i,
symbols[i].relative_pc, fieldWidth, mapName,
                        fieldWidth, symbolName,
pc_offset);
            } else {
                snprintf(line,
MAX_BACKTRACE_LINE_LENGTH, "#%02d  pc %08x  %.*s (%.*s)",
                        i,
symbols[i].relative_pc, fieldWidth, mapName,
                        fieldWidth, symbolName);
            }
        } else {
            snprintf(line,
MAX_BACKTRACE_LINE_LENGTH, "#%02d  pc %08x  %.*s",
                    i, symbols[i].relative_pc,
fieldWidth, mapName);
        }
 
        ALOGD("%s", line);
    }
 
    free_backtrace_symbols(symbols, count);
 
    return result;
}

对sched_policy.c的堆栈调用分析如下,注意具体是否要打印,在哪里打印,还可以通过pid、uid、property等来控制一下,这样就不会被淹死在trace的汪洋大海中。

D/SchedPolicy( 1350): #00  pc 0000676c 
/system/lib/libcutils.so
 
D/SchedPolicy( 1350): #01  pc 00006b3a 
/system/lib/libcutils.so (set_sched_policy+49)
 
D/SchedPolicy( 1350): #02  pc 00010e82 
/system/lib/libutils.so (androidSetThreadPriority+61)
 
D/SchedPolicy( 1350): #03  pc 00068104 
/system/lib/libandroid_runtime.so
(android_os_Process_setThreadPriority(_JNIEnv*, _jobject*, int,
int)+7)
 
D/SchedPolicy( 1350): #04  pc 0001e510 
/system/lib/libdvm.so (dvmPlatformInvoke+112)
 
D/SchedPolicy( 1350): #05  pc 0004d6aa 
/system/lib/libdvm.so (dvmCallJNIMethod(unsigned int const*, JValue*,
Method const*, Thread*)+417)
 
D/SchedPolicy( 1350): #06  pc 00027920 
/system/lib/libdvm.so
 
D/SchedPolicy( 1350): #07  pc 0002b7fc 
/system/lib/libdvm.so (dvmInterpret(Thread*, Method const*,
JValue*)+184)
 
D/SchedPolicy( 1350): #08  pc 00060c30 
/system/lib/libdvm.so (dvmCallMethodV(Thread*, Method const*,
Object*, bool, JValue*, std::__va_list)+271)
 
D/SchedPolicy( 1350): #09  pc 0004cd34 
/system/lib/libdvm.so
 
D/SchedPolicy( 1350): #10  pc 00049382 
/system/lib/libandroid_runtime.so
 
D/SchedPolicy( 1350): #11  pc 00065e52 
/system/lib/libandroid_runtime.so
 
D/SchedPolicy( 1350): #12  pc 0001435e 
/system/lib/libbinder.so
(android::BBinder::transact(unsigned int, android::Parcel const&,
android::Parcel*, unsigned int)+57)
 
D/SchedPolicy( 1350): #13  pc 00016f5a 
/system/lib/libbinder.so
(android::IPCThreadState::executeCommand(int)+513)
 
D/SchedPolicy( 1350): #14  pc 00017380 
/system/lib/libbinder.so
(android::IPCThreadState::joinThreadPool(bool)+183)
 
D/SchedPolicy( 1350): #15  pc 0001b160 
/system/lib/libbinder.so
 
D/SchedPolicy( 1350): #16  pc 00011264 
/system/lib/libutils.so (android::Thread::_threadLoop(void*)+111)
 
D/SchedPolicy( 1350): #17  pc 000469bc 
/system/lib/libandroid_runtime.so
(android::AndroidRuntime::javaThreadShell(void*)+63)
 
D/SchedPolicy( 1350): #18  pc 00010dca 
/system/lib/libutils.so
 
D/SchedPolicy( 1350): #19  pc 0000e3d8 
/system/lib/libc.so (__thread_entry+72)
 
D/SchedPolicy( 1350): #20  pc 0000dac4 
/system/lib/libc.so (pthread_create+160)
 
D/SchedPolicy( 1350): #00  pc 0000676c 
/system/lib/libcutils.so
 
D/SchedPolicy( 1350): #01  pc 00006b3a 
/system/lib/libcutils.so (set_sched_policy+49)
 
D/SchedPolicy( 1350): #02  pc 00016f26 
/system/lib/libbinder.so
(android::IPCThreadState::executeCommand(int)+461)
 
D/SchedPolicy( 1350): #03  pc 00017380 
/system/lib/libbinder.so
(android::IPCThreadState::joinThreadPool(bool)+183)
 
D/SchedPolicy( 1350): #04  pc 0001b160 
/system/lib/libbinder.so
 
D/SchedPolicy( 1350): #05  pc 00011264 
/system/lib/libutils.so (android::Thread::_threadLoop(void*)+111)
 
D/SchedPolicy( 1350): #06  pc 000469bc 
/system/lib/libandroid_runtime.so
(android::AndroidRuntime::javaThreadShell(void*)+63)
 
D/SchedPolicy( 1350): #07  pc 00010dca 
/system/lib/libutils.so
 
D/SchedPolicy( 1350): #08  pc 0000e3d8 
/system/lib/libc.so (__thread_entry+72)
 
D/SchedPolicy(
1350): #09  pc 0000dac4  /system/lib/libc.so (pthread_create+160)
Android C++层打印调用栈 在Android framework的C++层或其他C++服务中需要打印调用栈时,可以使用android中的CallStack类进行打印,该类的实现如下: /* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "Licen 阅读详情

相关推荐

Android9 C/C++打印调用栈的方法

一、C++打印调用栈 1.包含两个头文件 #include <utils/Log.h> #include <utils/CallStack.h> 2.编写打印调用栈函数 void dumping_callstack() { CallStack stack; //如果这里的函数不在android命名空间内,则要改为 android::CallStack stack; stack.update(); //输出到printf stack.dump(1); //输出

u012773843的博客 2208

Android 打印调用栈的方法

(1)打印本地调用堆栈。(2)打印远程调用堆栈。

xiaowang_lj的博客 1806

Android中获取调用栈信息的方法

在Android开发过程中,当我们遇到程序崩溃或异常时,常常需要获取调用栈信息以便于定位问题。Android提供了一种方法来获取当前的调用栈信息,即使用。数组,我们可以获取每个调用栈元素的类名、方法名和行号。最后,我们通过一个示例演示了如何使用该方法来获取并打印调用栈信息。接下来,我们可以通过一个简单的示例来演示如何使用上述代码获取调用栈信息。方法,我们可以轻松地获取当前的调用栈信息,并在需要时进行打印或其他处理。方法中,我们使用之前提到的方式来打印调用栈信息。方法来获取当前线程的调用栈信息。

TechBurst的博客 678

如何在 Android 方法中打印调用栈

在 Android 开发中,有时候我们需要调试方法的调用栈,以了解方法的调用顺序。这可以通过方法实现,并使用Log类打印调用栈信息。

weixin_45942995的博客 1195

Android 打印堆栈的几种方法

在Android调试过程中经常会出现程序出现的结果不是我们预期的结果,那就需要加Log打印调试,看调用过程是否正确,此时就需要打印程序的调用栈,特别是Android代码相当庞大,打印堆栈更有利于我们分析问题,下面就记录下平时用到不退出程序打印堆栈的方法。 验证的方法相关简单,在Activity的类中创建一个方法ThrowException,在onCreate中调用此方法,看打印出什么

xjbclz的专栏 7922

AST实战:解密Akamai混淆JS代码的完整流程

本文详细解析了如何使用AST技术解密Akamai混淆的JS代码,包括定位关键代码、AST解混淆实战步骤及常见问题解决方案。通过实际案例演示了从混淆代码到清晰逻辑的完整处理流程,并提供了工具推荐和法律合规建议,帮助开发者有效应对反爬虫技术。

weixin_33725722的博客 325

android native 调试 打印调用栈

在调试 android 某些应用时,需要打印调用栈, 但是高版本的5.0 以上已经去掉了libcorkscrew.so 和 libcutils.so 两个库, 改用其他的google 库文件,但是可以使用andorid 4.4 , 4.3 系统使用。 使用时可以直接调用 getCallStack()该方法即可。 android 6.0 可用 typedef int (*Unw_Bac...

明风的博客 3769

LangChain入门(二)-通过 Google 搜索并返回答案

并复制他给我们生成 api key。(博主使用了GitHub账号登录)-邮箱验证-手机号验证-订阅-api-key。Serpapi 提供了 google 搜索的 api 接口。首先需要我们到 Serpapi 官网上注册一个用户,

Good Luck 1万+

android java 调用栈_Android打印方法的调用栈

在需要打印调用栈的方法中调用 getStackTrace() 方法,该方法以字符串的形式返回调用栈。/*** 打印函数的调用栈** @return 调用栈*/public String getStackTrace() {StringBuilder sb = new StringBuilder("");Exception e = new Exception();StackTraceElement[]...

weixin_34996054的博客 683

MTK平台 MT6789 烧录 efuse 3.0 Configuration SOP

=====================生成cert1和cert2 key===============================================生成efuse key相关文件===========================================签名DA==========================================================正常编译。=====================Security3.0 的SOP 说明。

a785722173的博客 2334

NCBI|叶绿体基因组数据上传

叶绿体基因组NCBI上传 小编最近在NCBI上传了好几次数据…想着可以把具体的上传步骤写下来,供大家参考。以下是叶绿体基因组的上传示例,大家可以瞅瞅 图片 准备工作 1.登录NCBI官网:https://www.ncbi.nlm.nih.gov/, 依次点击“sign in to NCBI”——“See more 3rd party sign in options”——搜索“Microsoft live.com”。 ”sign in to NCBI“ ”See more 3rd party sign i

weifanbio的博客 3904

Android打印调用栈

打印调用栈是android平台问题定位的基本方法,如果需要知道谁在调用某个函数,可以在此函数中添加打印调用栈函数,弄清楚函数之间的调用关系。 1.Java层打印调用栈方法 RuntimeException here = new RuntimeException("here"); here.fillInStackTrace(); Log.w(TAG, "Called: " + thi

专注 专心 专业 1169

Qwen2.5-VL多模态微调超参数深度解析(上):训练流程与优化策略的量化机制分析

上篇文章通过系统化的对比实验,回答了多模态微调中的三个基础问题:“选什么方法”(LoRA/Full/Freeze/OFT对比)、“用什么配置”(60+组超参数组合)、“达到什么效果”(ROUGE-L/BLEU-4指标)。这些结果为后续工作奠定了实验基线,但也留下了更深层的疑问:为何相同方法在不同数据集上表现迥异?为何某些超参数的微小调整会引发性能剧变?如何在未见过的任务上快速找到最优配置?本文是对前文实验数据的二次挖掘与机理解析。我们将关注点从"做了什么实验"转移到"实验揭示了什么规律",实验视角从"结果对

羊城迷鹿的博客 1007

android java 调用栈_Android下打印调用栈

1. Java层如何打印调用栈?在优化Android启动过程时,同事给出一种打印出调用栈的函数。分享一下java.util.Map ts = Thread.getAllStackTraces();StackTraceElement[] ste = ts.get(Thread.currentThread());for (StackTraceElement s : ste) {android.util...

weixin_39999536的博客 202

33、Windows Server 2016 系统管理与安全防护指南

本文详细介绍了Windows Server 2016系统中的三大核心管理与安全功能:WSUS补丁管理、Windows Defender反恶意软件配置以及Windows Server Backup数据备份与恢复。涵盖WSUS初始同步、组策略配置客户端、混合环境更新评估流程;Windows Defender的图形化与PowerShell管理方式,以及通过组策略集中管控;Windows Server Backup的安装、单次与计划备份设置、增量备份机制和文件恢复操作。内容适用于企业IT管理员进行系统维护与安全防护

beta5的博客 97

置顶必读(3) |《滚雪球学SpringBoot》· 高质量专栏介绍,你值得拥有!

《滚雪球学SpringBoot》 并不是普通的技术讲解合集,它是专为开发者精心设计的系统化学习路径。通过不断“滚动学习”,我们将带领你从基础入门到高阶应用,从理解每一行代码到设计和优化大规模分布式系统,最终帮助你成长为一位精通 spring架构 的工程师。

**My Coding Family** 15万+

Android中打印调用栈

打印调用栈是android平台问题定位的基本方法,如果需要知道谁在调用某个函数,可以在此函数中添加打印调用栈函数,弄清楚函数之间的调用关系。 1. Java层打印调用栈方法 RuntimeException here = new RuntimeException("here"); here.fillInStackTrace(); Log.w(TAG, "Called: " + th

jcgu的专栏 1311

YOLO11检测中的内存占用分析与优化:讲解如何分析并优化推理时的内存使用

YOLOv11模型内存分析与优化摘要:本文系统分析了YOLOv11目标检测模型的内存使用模式,重点探讨了显存(VRAM)、系统内存(RAM)和共享内存的特性差异。通过PyTorch内置工具和自定义分析器,详细剖析了骨干网络、颈部网络和检测头各组件内存占用规律,指出激活值内存与输入尺寸呈平方级增长关系。文章提供了卷积层内存计算公式,并强调合理规划"工作台"(显存)与"仓库"(内存)间的数据流动是优化关键。最后通过流程图直观展示了YOLOv11推理过程的三类内存使用模式,

本博客聚焦 YOLOv11 全流程落地,涵盖架构优化、数据集处理、训练技巧与多场景部署,兼及国产数据库、Java 开发与 AI 模型应用,内容兼顾理论与工程实践,为开发者提供系统干货,助力高效提升技术能力。 344

Android在Log中打印出当前的调用栈

Android在Log中打印出当前的调用栈 Log.d(TAG,Log.getStackTraceString(new Throwable()));

tndroid的专栏 1917

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

Android下打印调用栈

Android下打印调用栈 1. Java层如何打印调用栈? 在优化Android启动过程时,同事给出一种打印出调用栈的函数。分享一下     java.util.Map ts = Thread.getAllStackTraces();       StackTraceElement[] ste = ts.get(Thread.currentThread());       f

wangkaiblog的专栏 939

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

android打印调用栈的方法

打印调用栈是android平台问题定位的基本方法,如果需要知道谁在调用某个函数,可以在此函数中添加打印调用栈函数,弄清楚函数之间的调用关系。 1. Java层打印调用栈方法 RuntimeException here = new RuntimeException("here"); here.fillInStackTrace(); Log.w(TAG, "Called: " + th

xzhang76 8978

Android C++层打印函数调用栈

1、添加头文件: #include <utils/CallStack.h> 2、在需要打印函数调用栈的函数中添加如下代码: CallStack stack; stack.update(); stack.log("LPM_DEBUG"); //后面字符串表示log中的包含字符,在查找时会比较方便 3、在函数文件对应的Android.mk中: LOCAL_SHARED_...

qq_24036115的博客 1904

Android的调用栈信息打印

打印调用栈是android平台问题定位的基本方法,如果需要知道谁在调用某个函数,可以在此函数中添加打印调用栈函数,弄清楚函数之间的调用关系。   1. Java层打印调用栈方法         // ------------------------------------------------------         RuntimeException here = new Runti

yytsweet的专栏 636
上一篇: RefPtr, passRefPtr, adoptRefPtr, OwnPtr
下一篇: 通过minidump查看crash的callstack
csshell2002
博客等级 码龄11年 30粉丝 41原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值