Skip to content

Avoid exception-driven control flow in ViewUtils.getResourceId #5632

Description

@runningcode

Problem

ViewUtils.getResourceId used exception-driven control flow: it threw Resources.NotFoundException for views with View.NO_ID or a generated id, and every caller caught and discarded it. This runs per view during view-hierarchy snapshots and gesture target resolution, so in Compose-heavy apps — where most views have generated ids — the SDK constructs an exception (plus a native fillInStackTrace stack walk) for nearly every view, on the main thread.

Found while analyzing this project's showcase Perfetto trace (sentryinvest): in a single view-hierarchy snapshot, 24 of 72 getResourceId calls threw Resources.NotFoundException on the main thread — pure overhead with no functional result.

Fix

Add a non-throwing ViewUtils.resolveResourceId(View) that returns null for unresolved ids, and route the hot callers (ViewHierarchyEventProcessor.viewToNode, AndroidViewGestureTargetLocator.createUiElement, getResourceIdWithFallback) through it. The public getResourceId(...) throws Resources.NotFoundException stays as a thin wrapper for backward compatibility. Emitted identifiers and fallbacks are unchanged.

On-device verification

Pixel 3 / Android 12, ART method tracing analyzed in Perfetto trace_processor, 2048 calls over NO_ID views:

old (getResourceId) new (resolveResourceId)
Resources$NotFoundException.<init> 2048 0
Throwable.fillInStackTrace 2048 0
total methods executed 30,757 12,324
inclusive time / call (traced) 30,470 ns 6,467 ns

One exception (+ native stack fill) per unresolved view removed; ~60% fewer executed methods, ~4.7× cheaper per unresolved view (absolute ns inflated by tracing — the counts and ratio are the reliable signal).

PR

#5631

Related follow-ups (from the same trace, not in this PR)

  • Speed up ViewUtils.findTarget (per-touch LinkedListArrayDeque; cache resource-name lookups).
  • Background JSON serialization cost in the vendored Gson JsonWriter.

Metadata

Metadata

Assignees

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions