Skip to main content

Hangs

The hang detector watches for situations where the main thread becomes unresponsive long enough to degrade the user experience, but the OS has not yet raised an ANR. When a hang is detected, Bugsee reports the main thread's stack alongside the usual video / logs / network context and produces an issue report.

Internally, the detector schedules a 1 s tick on a background thread; each tick posts a ping to the main thread's Looper. If a ping isn't acknowledged within the configured threshold, a hang at the matching severity is reported.

Configuration

FormSetting
Manifest meta-data<meta-data android:name="com.bugsee.option.detect.hang" android:value="true" />
Bugsee.launch() mapoptions.put(Options.DetectAndReportHang, true)
Defaultfalse
<meta-data android:name="com.bugsee.option.detect.hang"
android:value="true" />
tip

Hang detection is disabled by default. Enable it on internal / pre-release builds first to tune the thresholds against your app's real-world main-thread behavior before rolling out to production.

Severity thresholds

Hangs are graded into three severity bands. Each band has its own configurable threshold (in milliseconds); a hang is reported at the highest band whose threshold has been crossed.

SeverityDefault thresholdOption constantManifest key
Fair3 000 msOptions.DetectAndReportHangFairLevelcom.bugsee.option.detect.hang.level.fair
Medium5 000 msOptions.DetectAndReportHangMediumLevelcom.bugsee.option.detect.hang.level.medium
Severe10 000 msOptions.DetectAndReportHangSevereLevelcom.bugsee.option.detect.hang.level.severe

The three thresholds must satisfy Fair < Medium < Severe and all three must be positive. An out-of-order trio reverts the entire set to defaults (the SDK doesn't try to repair partial overrides).

Reports are deduplicated per call-site hash, so a single stuck call site doesn't flood Bugsee with reports during a long-running hang.

Culprit attribution

Once the main thread has been unresponsive for 1 s — before the Fair threshold can be crossed — the SDK starts a short-lived sampler that walks the main thread's stack every 200 ms for the rest of the freeze. When the report is generated, those samples are folded into the deepest, most persistent sub-stack they share, biased toward your own frames over framework plumbing. That culprit stack is what the report carries and what its grouping signature is derived from.

This replaces the single snapshot used before 7.2.0. A stack captured at the moment of reporting shows where the main thread ended up parked — routinely a framework frame — rather than the work that consumed the budget, which is why unrelated root causes used to collapse into one issue.

Consecutive identical samples are collapsed into a repeat count, the series keeps at most 80 distinct entries, and sampling stops after at most 50 walks (10 s at the default cadence) or as soon as the main thread recovers. No sampler thread, timer or allocation exists outside a freeze.

The report's thread list still carries the main thread's own stack, so nothing is lost. If sampling is disabled, arms too late, or produces nothing foldable, the report falls back to the single snapshot exactly as before.

FormSetting
Manifest meta-data<meta-data android:name="com.bugsee.option.detect.hang.sampling" android:value="false" />
Bugsee.launch() mapoptions.put(Options.DetectAndReportHangSampling, false)
Defaulttrue

DetectAndReportHangSampling only has an effect when DetectAndReportHang is enabled; it is a kill switch for the sampler, not a second way to turn hang detection on.

note

Hang issues group by the culprit stack, so hangs reported before and after the upgrade to 7.2.0 do not merge into the same issue.

ANRs are attributed the same way, under their own switch DetectAndReportAnrSampling (default true, effective only when DetectAndReportExitNotResponding is enabled). On API 30+ the samples are mirrored to disk while the freeze is in progress and folded into the ANR report on the next launch, and they are used only when they cover the ANR's timestamp. Sampling on that path arms only while the app is in the foreground, so a background ANR on API 30+ keeps the single main-thread stack parsed from the OS trace. See Abnormal exits.

See also

Found an issue, typo, or wrong statement on this page? Report it now →