Debugging App Freezes with HarmonyOS Enhanced Logs: Multi-Sampling Stack Analysis
This guide explains how HarmonyOS enhanced freeze logs use multi-sampling stack collection and CPU load analysis to precisely diagnose app freeze root causes, covering a four-step analysis workflow with concrete log examples.
Overview
When users experience unresponsive clicks or app freezes exceeding a time threshold, the system defines this as AppFreeze (application unresponsiveness). Starting from API 21 , HarmonyOS supports retrieving AppFreeze enhanced logs . These logs collect system-wide and main-thread runtime loads while capturing multiple main-thread call stacks, helping developers understand function call durations. Official documentation: https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/appfreeze-guidelines.
Two Causes of Freeze Screens
The article illustrates two primary freeze scenarios (referenced via diagram):
ThreadBlock3s : Main thread blocked for over 3 seconds.
InputBlock : Input event processing exceeds timeout.
Pain Points of Traditional Logs
When ThreadBlock3s and InputBlock events produce the following stack patterns, traditional logs fail to pinpoint the issue:
System Stacks — Main thread shows only system calls (e.g., kernel, EventHandler.process, EventRunner.Run), hiding business logic.
Instantaneous Stacks — A single stack snapshot captures a momentary slice, not the truly time-consuming function.
Developers only see a fragment of the call stack and cannot confirm which specific function consumes time.
Core Capabilities of Enhanced Logs
Enhanced logs solve these pain points through:
Collect Multiple Main-Thread Stacks — Capture call stacks repeatedly within a sampling period.
Record System & Main-Thread Loads — Assist in judging whether the thread actually obtained CPU execution time.
Sampling Stack & Duration Correlation Analysis — Identify time-consuming functions from multiple samples.
Enhanced Log Usage (Key Steps)
Step 1: Determine If Thread Obtained CPU Execution
Examine the CPU Time Statistics section:
CpuTime: 0 ms <- Main thread actual run time
SyncWaitTime: 2995 ms <- Main thread wait time
StaticsDuration: 2995 ms <- Total statistics durationJudgment Logic (illustrated in diagram): If CpuTime is near zero while SyncWaitTime ≈ StaticsDuration, the thread is blocked (not running). If CpuTime is significant, the thread is busy.
Step 2: Analyze CPU Utilization
Check CpuFreq Usage :
cpu0 Usage 23.5%, 1430MHZ 21.04%
cpu1 Usage 23.5%, 1430MHZ 21.04%
cpu2 Usage 23.5%, 1430MHZ 21.04%
cpu3 Usage 23.5%, 1430MHZ 21.04%Judgment Logic : If stack top is not blocked and CPU usage approaches 100%, consider system high-load issues; the freeze may be a scheduling problem and can be ignored.
Step 3: Parse Sampling Stacks
Enhanced logs collect multiple main-thread stacks. View the #ThreadInfos section:
#ThreadInfos Tid: 2204, Name: com.example.freeze
SnapshotTime: 2021-01-01-20-05-58.292875
#00 pc 00000000000015b8 [shmm](__kernel_gettimeofday+72)
#01 pc 00000000001d7e44 /system/lib64/ld-musl-aarck64.so.1(clock_gettime+48)
#02 pc 00000000001d9f20 /system/lib64/ld-musl-aarck64.so.1(time+32)
#03 pc 0000000000007e2c .../libsample.so(WaitSomeTime()+76)
...
========SubmitterStacktrace========
#00 pc 0000000000013108 /system/lib64/platformsdk/libuv.so(uv_queue_work+292)
#01 pc 0000000000008cdc .../libsample.so
#02 pc 000000000005ae00 .../libace_napi.z.so(...)
...Analysis Steps :
Count Call Path Occurrences — Find repeatedly appearing function calls across samples.
Extract Longest Common Path — Identify frequently executed code paths.
Estimate Duration — Calculate cumulative function time based on sample hits.
Example (from diagram): Assume 6 samples between ThreadBlock3s and InputBlock:
3 samples hit Task3 → Task3 consumes at least 900 ms.
3 samples hit Task4 → Task4 consumes at least 900 ms.
Step 4: Combine Multiple Stack Information
Correlate the following stacks (shown in diagram):
Traditional single stack
Enhanced sampling stacks
Submitter stack trace (async task origin)
Optimization Priority : Decide based on call-chain appearance frequency.
HarmonyOS Enhanced Log Example
Enhanced logs provide rich diagnostic data:
# CPU Time Analysis
CpuTime: 1500 ms <- Thread actually ran 1500ms
SyncWaitTime: 1500 ms <- Simultaneously waited 1500ms
StaticsDuration: 3000 ms <- Total statistics 3000ms
# First Sample (T=0ms)
SnapshotTime: 2021-01-01-20-05-58.292875
#00 WaitSomeTime()+76
#01 process()+200
#02 onInputEvent()+150
# Second Sample (T=300ms)
SnapshotTime: 2021-01-01-20-05-58.592875
#00 WaitSomeTime()+76
#01 process()+200
#02 onInputEvent()+150
# Third Sample (T=600ms)
SnapshotTime: 2021-01-01-20-05-58.892875
#00 WaitSomeTime()+76
#01 process()+200
#02 onInputEvent()+150Value : Three consecutive samples hit WaitSomeTime, proving this function continuously blocked for at least 600 ms.
Sampling Stack Location Effectiveness
Scenario 1: System Stacks Cannot Locate Issue
Traditional Log :
#00 [kernel]
#01 EventHandler.process()
#02 EventRunner.Run()Only knows it's in process; cannot confirm which sub-function is slow.
HarmonyOS Enhanced Log :
# Sample1: process() -> group_api() -> render()
# Sample2: process() -> group_api() -> render()
# Sample3: process() -> list_builder() -> item_create()Clearly shows group_api hit multiple times — the root cause.
Scenario 2: Busy-Type Problem Location
When thread is busy but unknown what it's doing, enhanced logs' multiple samples cover the full execution path; estimate relative duration from sample counts.
Sample1: Task3 -> funcA -> funcB (hit)
Sample2: Task3 -> funcA -> funcC (hit)
Sample3: Task4 -> funcD -> funcE (hit)
Sample4: Task4 -> funcD -> funcE (hit)Confirms Task3 and Task4 each executed twice; combine with total duration to estimate single-run time.
Scenario 3: Async Task Traceback
When sampling originates from uv_queue_work, HarmonyOS enhanced logs stitch the complete task submitter stack:
========SubmitterStacktrace========
#00 uv_queue_work+292
#01 libsample.so
#02 ArkNativeFunctionCallBack()
#03 RTStub_PushCallArgsAndDispatchNative()
#04 BCStub_HandleCallthis0Imm8V8StwCopy+372
#05 at Index.ts:381:36 <- Traced to exact JS code lineCore Advantage : The sampling stack mechanism transforms "instantaneous slices" into "time series", especially suited for hard-to-locate busy-type and system-stack-dense issues. The diagram shows the complete bottleneck sequence in the appfreeze_threadblock simulation function.
Summary
The core value of freeze enhanced logs lies in: converting "instantaneous slices" into "time series" , enabling developers to trace the main thread's complete execution trajectory over a period and precisely locate busy-type freeze root causes.
Enhanced Log Usage Mnemonic :
Check CpuTime First — Determine blocking vs. busy.
Check CPU Usage Next — Confirm scheduling issues.
Then Parse Sampling Stacks — Find time-consuming functions.
Combine Multi-Stack Analysis — Set optimization priority.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
HarmonyOS Developer Technology
HarmonyOS developers provide key technology analysis, version updates, Codelabs practice, and event information for HarmonyOS. Welcome developers to join the HarmonyOS ecosystem and create infinite possibilities together!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
