當前位置:首頁 » 安卓系統 » android調用棧

android調用棧

發布時間: 2022-10-09 09:31:29

① Android webkit怎麼列印函數調用棧呢

棧函數很多都沒

② 如何調試分析Android中發生的tombstone

Android中較容易出現以下三類問題:Force close / ANR / Tombstone

前兩者主要是查看當前的進程或者系統框架層的狀態和堆棧就基本可以分析出來,本文主要討論一下tombstone的情況。

tombstone一般是由Dalvik錯誤、狀態監視調試器、C層代碼以及libc的一些問題導致的。


系統發生tombstone的時候,kernel首先會上報一個嚴重的警告信號(signal),上層接收到之後,進程的調試工具會把進程中當時的調用棧
現場保存起來,並在系統創建了data/tombstones目錄後把異常時的進程信息寫在此目錄裡面,開發者需要通過調用棧來分析整個調用流程來找出出
問題的點。

基本工具:

prebuilt/linux-x86/toolchain/arm-eabi-4.4.0/bin

在分析的時候仔細讀取匯編會獲得更多有用的異常發生時的信息。

1.arm-eabi-addr2line 將類似libxxx.so 0x00012345的調用棧16進制值翻譯成文件名和函數名

arm-eabi-addr2line -e libxxx.so 0x00012345

2.arm-eabi-nm 列出文件的符號信息

arm-eabi-nm -l -C -n -S libdvm.so > dvm.data

3.arm-eabi-objmp 列出文件的詳細信息

arm-eabi-objmp -C -d libc.so > libc.s

通過以上工具的分析 ,我們可以得到較完整的調用棧以及調用邏輯的匯編碼。

然後需要結合ARM架構及ARM匯編的知識(有些情況下可能需要使用gdb)

來分析出現tombstone的原因,以下是本人遇到過的一些tombstone的情況:

1.無效的函數指針:指針為NULL或者已經被重新賦值

2.strlen崩潰:導致不完全的棧信息,棧被破壞
3.FILE操作:因為stdio並非線程安全的,多線程操作時,容易出現異常。

望採納。

③ android 主線程棧native代表什麼意思

調用棧的作用, 棧可以記錄你運行中的函數調用(或者叫做函數執行順序), 每個線程都有一個獨自的調用棧, 至於為什麼, 你可以想一下, 如果線程和調用它的進程共用調用棧的話, 線程還能並行進行么? 調用棧記錄了運行順序, 開創獨立的棧的原因就是為了並行進行.... 這就是線程最重要的作用

④ 如何調試分析android中發生的tombstone

1.arm-eabi-addr2line 將類似libxxx.so 0x00012345的調用棧16進制值翻譯成文件名和函數名
arm-eabi-addr2line -e libxxx.so 0x00012345
2.arm-eabi-nm 列出文件的符號信息
arm-eabi-nm -l -C -n -S libdvm.so > dvm.data
3.arm-eabi-objmp 列出文件的詳細信息
arm-eabi-objmp -C -d libc.so > libc.s
通過以上工具的分析 ,我們可以得到較完整的調用棧以及調用邏輯的匯編碼。
然後需要結合ARM架構及ARM匯編的知識(有些情況下可能需要使用gdb)
來分析出現tombstone的原因,以下是本人遇到過的一些tombstone的情況:
1.無效的函數指針:指針為NULL或者已經被重新賦值
2.strlen崩潰:導致不完全的棧信息,棧被破壞
3.FILE操作:因為stdio並非線程安全的,多線程操作時,容易出現異常。

⑤ Android 10.0 Activity的啟動流程

本文主要學習記錄,基於Android 10的源碼,有錯誤歡迎指正,主要目的是梳理流程圖。

以進程為單位的調用棧圖如下:

1.activity中的startActivity方法最終都會通過拿到ATSM的代理IActivityTaskManager調用的startActivity;

2.之後進入system server進程中的ATMS startActivity,ATMS 經過收集Intent信息,然後使用ActivityStackSupervisor.startSpecificActivityLocked,如果進程已經存在,則直接使用realStartActivityLocked,通過App的binder客戶端的代理ApplicationThread調用回到bindApplication,走入Activity的啟動流程;如果進程不存在則通過socket鏈接Zygote,請求fork新的進程;

3.App進程創建完成後,進程啟動會調用ActivityThread.main方法,初始化主線程Handler,接著走入attach方法,然後通過AMS的代理調用AMS的attachApplication方法,並將App進程的通信代理ApplicationThread傳入AMS;

4.AMS獲取到ATMS調用ApplicationThread的bindApplication回到App進程的ActivityThread.ApplicationThread.bindApplication方法中,然後使用Handler切換到主線程執行handleBindApplication,這里初始化了App的進程名字、時間,用戶的硬體配置,包括App的文件系統,創建了App的Context實例,Instrumentation實例,調用App的onCreate回調方法,同時告訴AMS APP初始化工作完畢;

5.AMS接著會調用ATMS的attachApplication,最後調用ClientLifecycleManager的scheleTransaction方法,通過App的Binder代理ApplicationThread回到ActivityThread;

6.進入ActivityThread.ApplicationThread.scheleTransaction方法之後就進入了Activity的onStart、onResume回調

創建進程之前的過程主要是AMS的內部信息收集的判斷的過程,下面主要看一下App進程啟動的源碼流程

從應用進程被創建開始,ActivityThread.main被執行

調用ActivityThread的attach方法,然後將activity和AMS通信的Binder代理IApplicationThread實例傳入AMS

接著進入AMS進程,ActivityManagerService.attachApplicationLocked

1.thread.bindApplication :該方法主要講App進程的配置信息通過IApplicationThread Binder通信回傳到ActivityThread中

2.mAtmInternal.attachApplication :mAtmInternal實際就是ActivityTaskManager的實例,通過LocalServices載入

那麼這里相當於走到了ActivityTaskManagerServer的attachApplication中

先看第一條:

注意:ActivityThread中存在於Binder通信的代理--》ApplicationThread extends IApplicationThread.Stub

ActivityThread--》ApplicationThread--》bindApplication

這里的bindApplication主要初始化了AppBindData,然後發送BIND_APPLICATION給APP的主線程BIND_APPLICATION,最後執行了handleBindApplication

handleBindApplication如下:

ActivityThread--》class H extends Handler

該方法主要在App進程中對App的一些硬體資源配置申請的屬性、App的文件夾等完成App基本信息的初始化

接著看第二條:mAtmInternal.attachApplication

mAtmInternal.attachApplication最終會調用mRootActivityContainer.attachApplication(wpc)

RootActivityContainer.attachApplication

接著調用ActivityStackSupervisor.realStartActivityLocked開始創建Activity

ActivityStackSupervisor.realStartActivityLocked

創建ClientLifecycleManager和ClientTransactionHandler來輔助管理Activity的生命周期

注意

clientTransaction.addCallback是LaunchActivityItem

lifecycleItem是ResumeActivityItem

ClientLifecycleManager.scheleTransaction最終會調用ClientTransaction的schele方法

那麼這個mClient是IApplicationThread的實例,那麼此時也就回到了ActivityThread的ApplicationThread中

ActivityThread的ApplicationThread中

因為ActivityThread繼承ClientTransactionHandler,所以到了ClientTransactionHandler中

通過Handler發送消息EXECUTE_TRANSACTION到H中

接著TransactionExecutor的execute方法

LaunchActivityItem.execute方法

client其實是在ActivityThread的實例,那麼就回到了ActivityThread的handleLaunchActivity

接著調用performLaunchActivity

在performLaunchActivity中,主要是載入App的資源包,然後創建了Activity的context實例,並創建了Activity的實例,接著調用activity.attach方法,attach執行完之後調用了onCreate方法。

activity.attach

activity.attach中主要

1.創建了PhoneWindow實例

2.設置了Window介面的監聽

3.初始化了成員變數,包括線程和WindowManager

到此Oncreate已經完成,那麼OnStart和OnResume去哪了?

TransactionExecutor的execute方法

之前們只分析了executeCallbacks,接著executeLifecycleState方法

TransactionExecutor的executeLifecycleState方法

cycleToPath:lifecycleItem即為ResumeActivityItem

第一點:

int finish = lifecycleItem.getTargetState()

lifecycleItem對應ResumeActivityItem,如下:

ResumeActivityItem的getTargetState方法

對應ActivityLifecycleItem中的枚舉類型:

第二點:ActivityClientRecord中的mLifecycleState,由於在前面已經執行了handleLaunchActivity所以mLifecycleState=1

對應ActivityLifecycleItem中的枚舉類型:

PRE_ON_CREATE = 0

所以final int star = 1

接著看getLifecyclePath,此時start=1,finish=3

那麼返回的IntArray就是2

接著看performLifecycleSequence

最終執行的是handleStartActivity所以最終走到了ActivityThread的handleResumeActivity

兩點:

調用activity.performStart

調用Instrumetation.callActivityOnPostCreate

performStart方法:

調用了Instrumentation.callActivityOnStart方法:

最終到了activity的onStart方法

第二點:Instrumentation.callActivityOnPostCreate

上面主要走了cycleToPath,接著ResumeActivityItem.execute

調用了handleResumeActivity方法

handleResumeActivity最終調用performResumeActivity

調用了Instrumentation.callActivityOnResume,

到了activity.onResume()方法

參考文章: https://blog.csdn.net/u011386173/article/details/87802765

⑥ Android App內存優化

內存優化就是對內存問題的一個預防和解決,做內存優化能讓應用掛得少、活得好和活得久。

掛的少:
「掛」指的是 Crash,內存問題導致 Crash 的具體表現就是內存溢出異常 OOM。

活得好:
活得好指的是使用流暢,Android 中造成界面卡頓的原因有很多種,其中一種就是由內存問題引起的。內存問題之所以會影響到界面流暢度,是因為垃圾回收(GC,Garbage Collection),在 GC 時,所有線程都要停止,包括主線程,當 GC 和繪制界面的操作同時觸發時,繪制的執行就會被擱置,導致掉幀,也就是界面卡頓。

活得久:
活得久指的是我們的應用在後台運行時不會被幹掉。Android 會按照特定的機制清理進程,清理進程時優先會考慮清理後台進程。清理進程的機制就是LowMemoryKiller。在 Android 中不同的進程有著不同的優先順序,當兩個進程的優先順序相同時,低殺會優先考慮幹掉消耗內存更多的進程。也就是如果我們應用佔用的內存比其他應用少,並且處於後台時,我們的應用能在後台活下來,這也是內存優化為我們應用帶來競爭力的一個直接體現。

內存佔用是否越少越好?
當系統 內存充足 的時候,我們可以多用 一些獲得更好的性能。當系統 內存不足 的時候,我們希望可以做到 」用時分配,及時釋放「。內存優化並不能一刀切。

我們都知道,應用程序的內存分配和垃圾回收都是由Android虛擬機完成的,在Android 5.0以下,使用的是Dalvik虛擬機,5.0及以上,則使用的是ART虛擬機。
Android虛擬機Dalvik和ART

1、內存區域劃分

詳細請看以下兩篇文章(建議全看):
java內存四大區_JVM內存區域劃分
Android 內存機制

2、內存回收

垃圾收集的標記演算法(找到垃圾):

垃圾收集演算法(回收垃圾):

引用類型:強引用、軟引用、弱引用、虛引用

對象的有效性=可達性+引用類型

JAVA垃圾回收機制-史上最容易理解看這一篇就夠了
Android:玩轉垃圾回收機制與分代回收策略

android中還存在低殺機制,這種情況屬於系統整機內存不足,直接把應用進程殺掉的情況。

Android後台殺死系列:LowMemoryKiller原理

1、內存溢出
系統會給每個App分配內存空間也就是heap size值,當app佔用的內存加上申請的內存超過這個系統分配的內存限額,最終導致OOM(OutOfMemory)使程序崩潰。

通過命令 getprop |grep dalvik.vm.heapsize 可以獲取系統允許的最大
注意:在設置了heapgrowthlimit的狀況下,單個進程可用最大內存為heapgrowthlimit值。在android開發中,若是要使用大堆,須要在manifest中指定android:largeHeap為true,這樣dvm heap最大可達heapsize。
關於heapsize & heapgrowthlimit

2、內存泄漏
Android系統虛擬機的垃圾回收是通過虛擬機GC機制來實現的。GC會選擇一些還存活的對象作為內存遍歷的根節點GC Roots,通過對GC Roots的可達性來判斷是否需要回收。內存泄漏就是 在當前應用周期內不再使用的對象被GC Roots引用,造成該對象無法被系統回收,以致該對象在堆中所佔用的內存單元無法被釋放而造成內存空間浪費,使實際可使用內存變小。簡言之,就是 對象被持有導致無法釋放或不能按照對象正常的生命周期進行釋放。
Android常見內存泄漏匯總

3、內存抖動
指的是在短時間內大量的新對象被實例化,運行時可能無法承載這樣的內存分配,在這種情況下就會導致垃圾回收事件被大量調用,影響到應用程序的UI和整體性能,最終可能導致卡頓和OOM。
常見情況:在一些被頻繁調用的方法內不斷地創建對象。例如在View 的onDraw方法內new 一些新的對象。

注意內存抖動也會導致 OOM,主要原因有如下兩點:

1、Android Studio Profiler

作用

優點

內存抖動問題處理實戰

理解內存抖動的概念的話,我們就能明白只要能找到抖動過程中所產生的對象及其調用棧,我們就能解決問題,剛好Android Studio 的Porfiler裡面的Memory工具就能幫我們記錄下我們操作過程中或靜止界面所產生的新對象,並且能清晰看到這些對象的調用棧。

選擇Profile 中 的Memory ,選擇 Record Java/Kotlin allocations,再點擊Record開始記錄, Record Java/Kotlin allocations 選項會記錄下新增的對象。

操作完成之後,點擊如圖所示的紅腦按鈕,停止記錄。

停止記錄後,我們就可以排序(點擊 Allocations可以排序)看看哪些對象或基本類型在短時間被頻繁創建多個,點擊這些新增的對象就可以看到它的完成的調用鏈了,進而就找找到導致內存抖動的地方在哪裡了。

2、利用DDMS 和 MAT(Memory Analyzer tool)來分析內存泄漏

我們利用工具進行內存泄漏分析主要是用對比法:
a.先打開正常界面,不做任何操作,先抓取一開始的堆文件。
b.一頓胡亂操作,回到原來操作前的界面。主動觸發一兩次GC,過10秒再抓取第二次堆文件。
c.通過工具對比,獲取胡亂操作後新增的對象,然後分析這些新增的對象。

DDMS作用:抓取堆文件,主動觸發GC。(其實也是可以用Android Studio 的Profile裡面的Memory工具來抓取堆文件的,但是我這邊在利用Profile 主動觸發gc 的時候會導致程序奔潰,也不知道是不是手機的問題,所以沒用Android Studio的Profiler)

MAT作用:對堆文件進行對比,找到多出的對象,找到對象的強引用調用鏈。

以下是詳細的過程:

步驟1.打開DDMS,選擇需要調試的應用,打開初始界面,點擊下圖的圖標(Dump Hprof File)先獲取一次堆文件。

步驟2.對應用隨便操作後,回到一開始的界面,先多觸發幾次GC ,點擊下圖的圖標(Cause Gc)來主動觸發GC,然後再次點擊 Dump Hprof File 圖標來獲取堆文件。

步驟3.通過Android Studio Profile 或者 DDMS mp 的堆文件無法在MAT 打開,需要藉助android sdk包下的一個工具hprof-conv.exe來轉換。

格式為 hprof-conv 舊文件路徑名 要轉換的名稱;
例如:hprof-conv 2022-04-13_17-54-40_827.hprof change.hprof

步驟4.把兩份堆文件導入MAT,然後選擇其中第二次獲取的堆文件,點擊 如圖所示的 Histogram查看。

步驟5.點擊下圖圖標,Compare To Another Heap Dump ,選擇另一份堆文件。

6.會得出下圖所示的 Hitogram 展示,我們主要看Objects 這一列。 如下圖所示 「+ 2」 則代表前面兩份堆文件對比,這個對象多了兩個,我們主要就是要分析這些多了出來,沒有被回收的對象。

7.加入我們從增加的對象中,看到了MainActivity ,則需要從一開始打開的Hitogram 展示裡面找到這個對象的調用棧。如下圖所示,搜索MainActivity

8.看到下圖所示解僱,然後滑鼠右鍵點擊下圖紅色圈圈著的MainActivity ,選擇 Merger Shortest Paths to Gc Roots ,再選擇 exclude all phantom/weak/soft etc.references ,就可以看到這個MainActivity 對象的強引用鏈,至此我們就可以找到MainActivity對象是被什麼引用導致無法回收了。

3、內存泄露檢測神器之LeakCanary(線下集成)

自行學習了解,接入簡單,使用簡單,基本可以解決大部分內存泄漏問題。
github地址 : https://github.com/square/leakcanary/
學習地址 : https://square.github.io/leakcanary/changelog/#version-22-2020-02-05

針對內存抖動的建議:

針對內存泄漏問題的建議:

針對內存溢出問題的建議(主要就是要減少內存佔用):

建議參考:
深入探索 Android 內存優化(煉獄級別)

對於 優化的大方向,我們應該優先去做見效快的地方,主要有以下三部分:內存泄漏、內存抖動、Bitmap。完善監控機制也是我們的重點,能幫助我們對內存問題快速分析和處理。

參考:
深入探索 Android 內存優化(煉獄級別)

⑦ android怎樣將activity放入全局棧

Activity是Android程序的表現層。程序的每一個顯示屏幕就是一個Activity。正在運行的Activity處在棧的最頂端,它是運行狀態的。

當有新的Activity進入屏幕最上端時,原來的Activity就會被壓入第二層。如果他的屏幕沒有被完 全遮蓋,那麼他處於Paused狀態,如果他被遮蓋那麼處於Stop狀態。
不管處於任何一層,都可能在系統覺得資源不足時被強行關閉,當然關閉時棧底的程序最先被關閉。
譬如:當你在程序中調用 Activity.finish()方法時,結果和用戶按下 BACK 鍵一樣:他告訴 Activity Manager該Activity實例可以被「回收」。隨後 Activity Manager 激活處於棧第二層的 Activity 並重 新入棧,把原 Activity 壓入到棧的第二層,從 Running 狀態轉到 Paused 狀態。

在BlackBerry中,提供了一個管理Screen的棧,用來從任何地方來關閉位於最上一層的Screen,使用UiApplication.getUiApplication().getActiveScreen()來得到位於最上一層的Screen的實例,並且使用UiApplication.getUiApplication().popScreen()來關閉一個Screen或關閉當前最上一層的Screen,但是Android卻未提供相應的功能,只能在一個Activity的對象裡面調用finish來關閉自己,不能關閉其他的Activity。比如我們想實現一個功能從屏幕A—>屏幕B—>屏幕C—>屏幕D,然後在在轉到屏幕D之前將屏幕B和C關閉,在屏幕B和屏幕C界面點擊會退按鈕都可以回退到上一個屏幕,但是在屏幕D上點擊會退按鈕讓其回退到A,此外在一些循環跳轉的界面上如果不在合適的地方將一些不需要的屏幕關閉,那麼經過多次跳轉後回導致內存溢出。對此我們可以設計一個全局的Activity棧,使用這個棧來管理Activity。管理Activity的類的定義如下:

import java.util.Stack;

import android.app.Activity;

public class ScreenManager {
private static Stack activityStack;
private static ScreenManager instance;
private ScreenManager(){
}
public static ScreenManager getScreenManager(){
if(instance==null){

⑧ Android-Choreographer 垂直同步 Vsync

view.requestLayout 調用的是 parent.requestLayout,直到 DecorView 最終到 ViewRootImpl.requestLayout 方法。

提示: requestLayout() 跟 invalidate() 區別在於 PFLAG_FORCE_LAYOUT、PFLAG_INVALIDATED,invalidate 不會重新測量布局,只會重新繪制

調用棧:mChoreographer.postCallback(int callbackType, Runnable action, Object token) --> postCallbackDelayed() --> postCallbackDelayedInternal()

至此從調用 requestLayout 到請求 Vsync 信號過程已經結束。
下面看收到 Vsync 信號後,如何處理 mTraversalRunnable 任務。

doTraversal()方法則是 測量、布局、繪制 入口,此處不做分析。

Vsync 垂直同步:
    涉及到垂直刷新脈沖、vsync 、gpu 緩沖區 Frame Buffer、Back Buffer 三重緩存,跟 Choreographer
    gpu 像素柵格化
    垂直同步使得顯卡的輸出幀數和屏幕的刷新速度保持一致,其中 vsync 用來同步信息,buffer 緩存數據,當 vsync 出現時,cpu 會立即處理下一幀數據寫入到緩存中,
    之後gpu再渲染數據寫在同一個緩存中,當vsync時,下一幀的 buffer 跟當前幀所在的buffer數據交換,當如果之前幀未顯示完,是不會進行數據交換的。屏幕掃描下一次的數據顯示。
    當一個信號來時,假設a b buffer都被佔用,此時gpu使用c緩存下一幀的數據,可以有效減少掉幀的幾率。

1、view.requestLayout 調用的是 parent.requestLayout ,直到 DecorView 最終到 ViewRootImpl.requestLayout 方法。
2、首先判斷正在測量布局,沒有則 checkThread 檢驗當前是否在主線程。在 scheleTraversals 首先中執行同步屏障,其次再將任務 postCallback 給 Choreographer,Choreographer 將任務保存在 mCallbackQueues 中,同時發送 MSG_DO_SCHEDULE_CALLBACK 的同步消息給FrameHandler。FrameHandler 的優先執行 CALLBACK 同步消息調用 doScheleCallback,mCallbackQueues 不為空且 callback 不是延遲執行,調用 scheleFrameLocked 方法請求 Vsync 信號。當運行在 Looper 線程,則立刻調度 vsync,否則,發送消息到UI線程再調度 vsync。其中是通過 FrameDisplayEventReceiver 調度 vysnc。

FrameDisplayEventReceiver 有兩個作用,一個是 scheleVsync 請求調度,另一個是接收 vsync 信號回調 onVsync,當接收到 vsync 信號時,調用doFrame 方法,開始渲染下一幀。

doFrame 可以分為三步:一是計算掉幀邏輯,二是記錄幀繪制信息,三是處理多種 callback,依次是 input 調用棧,會回調到 DecorView 的 dispatchTouchEvent。
二是 animation 調用棧,執行動畫;三是 Traversal 調用棧,即最發送給 Choreographer 的任務

動畫如何流暢執行: 調用animation.start時,最終在AnimationHandler會給Choreographer.FrameCallback 回調 doFrame,裡面 post了自己。

⑨ android列印調用堆棧

修改Android.bp,加入callstack模塊

注意這里android是命名空間,如果已經在android命名空間內則不需要寫android::

⑩ 如何打出Android程序調用stack trace

找出程序的調用堆棧 trace 可以知道是誰調用了這個介面,也能快速學習程序的調用流程,非常實用。但需要注意的是,不能在正式代碼中使用,只能用於調試,這個非常耗資源也會造成 log 泛濫。

下面就介紹如何在 Android Java/C++/C 程序當中列印出程序調用 trace,如果需要在其他環境中使用的話 C++/C 部分需要移植 corkscrew 庫。

Java
非常簡單,創建一個 Throwable 對象,就可以得到當前的 stack trace。下面例子是打出調用 foobar() 函數的 trace:

1 private void foobar() {
2 Throwable t = new Throwable();
3 Log.d(TAG, "stack trace is ", t);
4 }
C++
也比較簡單,使用 utils/Callstack 類即可。頭文件位於 frameworks/native/include/utils/CallStack.h,一般無需修改 Android.mk 可直接使用。下面例子是打出調用 Foo::bar() 函數的 trace:

復制代碼
1 #include <utils/CallStack.h>
2
3 void Foo::bar() {
4 // CallStack::CallStack(const char* logtag, int32_t ignoreDepth, int32_t maxDepth)
5 CallStack *t = new CallStack("Trace", 1, 30);
6 delete t;
7 }
復制代碼
C
稍微麻煩一點,需要直接調用 corkscrew/backtrace。其實 C++ 里的 utils/Callstack 也是使用 corkscrew/backtrace,只是進行了封裝更易於使用。我們參照 CallStack.cpp 裡面代碼即可。下面例子是打出調用 foobar() 函數的 trace:

NOTE: C 不能直接調用 C++ 代碼,除非在 C++ 類中添加相應的 C wrapper,或者通過 dlsym 動態載入。

復制代碼
1 #include <corkscrew/backtrace.h>
2
3 void mpStackTrace(const char* logtag, int32_t ignoreDepth, int32_t maxDepth) const {
4 static const int MAX_DEPTH = 31;
5 static const int MAX_BACKTRACE_LINE_LENGTH = 800;
6
7 if (maxDepth > MAX_DEPTH) {
8 maxDepth = MAX_DEPTH;
9 }
10 backtrace_frame_t mStack[MAX_DEPTH];
11 ssize_t count = unwind_backtrace(mStack, ignoreDepth + 1, maxDepth);
12 if (count <= 0) {
13 LOGE("Can not get stack trace");
14 return;
15 }
16
17 backtrace_symbol_t symbols[count];
18
19 get_backtrace_symbols(mStack, count, symbols);
20 for (size_t i = 0; i < count; i++) {
21 char line[MAX_BACKTRACE_LINE_LENGTH];
22 format_backtrace_line(i, &mStack[i], &symbols[i],
23 line, MAX_BACKTRACE_LINE_LENGTH);
24 ALOG(LOG_DEBUG, logtag, "%s%s",
25 "",
26 line);
27 }
28 free_backtrace_symbols(symbols, count);
29 }
30
31 void foobar() {
32 mpStackTrace("Trace", 1, 30);
33 }
復制代碼
頭文件位於 system/core/include/corkscrew/backtrace.h,在 Android.mk 中還需要加入:

1 LOCAL_SHARED_LIBRARIES += libcorkscrew

熱點內容
lol破解腳本 發布:2025-01-23 02:07:54 瀏覽:129
演算法是步驟 發布:2025-01-23 01:47:22 瀏覽:237
ip訪問控制實驗 發布:2025-01-23 01:41:51 瀏覽:105
crv20萬能落地什麼配置 發布:2025-01-23 01:35:33 瀏覽:172
s10手機怎麼查配置 發布:2025-01-23 01:34:48 瀏覽:890
九陰真經3d免費腳本 發布:2025-01-23 01:33:47 瀏覽:686
gcc編譯分為哪幾個階段 發布:2025-01-23 01:33:45 瀏覽:806
戰地5怎麼看哪個伺服器 發布:2025-01-23 01:33:07 瀏覽:367
首選域名伺服器怎麼設置 發布:2025-01-23 01:32:18 瀏覽:156
android手機代理 發布:2025-01-23 01:28:42 瀏覽:113