Skip to content

RUM-15103: Fixcompose-ui compatibility issue#3303

Merged
satween merged 2 commits intodevelopfrom
tvaleev/feature/RUM-15103
Apr 7, 2026
Merged

RUM-15103: Fixcompose-ui compatibility issue#3303
satween merged 2 commits intodevelopfrom
tvaleev/feature/RUM-15103

Conversation

@satween
Copy link
Copy Markdown
Contributor

@satween satween commented Mar 27, 2026

What does this PR do?

Fix compatibility with the latest compose-ui where Google migrated from android-compose to KMP-compatible Compose. This change caused method mangling differences — the Kotlin compiler now adds $ui suffix instead of $ui_release for internal members.

Added reflection-based fallback in getLayoutNodeBoundsInWindow() that searches for methods without $ suffix with the new getMethod() helper.

Screenshot 2026-03-27 at 16 17 05

Motivation

Google's migration of Compose to KMP-compatible version (https://android-review.googlesource.com/c/platform/frameworks/support/+/3684165) introduced breaking changes in method mangling for internal members. Our SDK is compiled with Compose BOM 2023.10.01, and upgrading would pull in kotlin-coroutines dependencies that some users don't want.

Before fix After fix
Screen_recording_20260327_161101.webm
Screen_recording_20260327_161522.webm

@satween satween requested review from a team as code owners March 27, 2026 21:14
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 59559d79b3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +101 to +103
return runSafe("getLayoutNodeBoundsInWindow") {
node.layoutDelegate.outerCoordinator.coordinates.boundsInWindow()
} ?: runSafe("getLayoutNodeBoundsInWindow[reflection]") {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Avoid throwing on every bounds lookup in new Compose runtime

When the app runs with the newer Compose artifact (where internal getters are mangled as $ui), the direct call in getLayoutNodeBoundsInWindow() fails first and only then falls back to reflection. Because hitTest() calls this for every traversed LayoutNode, this means a NoSuchMethodError is thrown and caught repeatedly on the hot path for each tap/scroll, which can cause significant jank/perf regression even though the fallback eventually succeeds. Consider short-circuiting to the reflection path after the first compatibility failure (or caching the successful access strategy) instead of retrying the failing direct path every time.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is a valid point. I'm wondering if we can read Compose version used to compile and use version-related strategy for the app lifetime, hitting the same path.

However, I'm not sure at which stage these methods are generated: maybe we can have a mix of naming conventions from different Compose versions (e.g. 3rd-party lib composables + user-owned composables) in the same app?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there isn't an easy way of reading compose version at runtime, at least we can have a simple variable of caching the result of reflection path to avoid to always retry the failing path.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caching can be the option. Maybe we can think about then reading version from classpath and generating version property in Gradle Plugin. But we need to make sure that all Compose-related code sites are produced by the same Compose compiler version then.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'am not sure that caching here gonna save a lot, because reflection is a fallback here, not the main scenario, but let's add them for any potential case.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is a fallback, but it is a persistent fallback, because this is for the static code. This fallback can be hit many times (all the time for the particular element).

@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Mar 27, 2026

Codecov Report

❌ Patch coverage is 58.82353% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 71.55%. Comparing base (7ff6870) to head (7217f8b).

Files with missing lines Patch % Lines
.../android/compose/internal/utils/LayoutNodeUtils.kt 58.82% 3 Missing and 4 partials ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #3303      +/-   ##
===========================================
+ Coverage    71.52%   71.55%   +0.03%     
===========================================
  Files          946      946              
  Lines        34895    34910      +15     
  Branches      5909     5916       +7     
===========================================
+ Hits         24956    24978      +22     
+ Misses        8270     8265       -5     
+ Partials      1669     1667       -2     
Files with missing lines Coverage Δ
.../android/compose/internal/utils/LayoutNodeUtils.kt 71.83% <58.82%> (-1.38%) ⬇️

... and 31 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@mariusc83 mariusc83 closed this Apr 2, 2026
@0xnm 0xnm reopened this Apr 2, 2026
@satween satween force-pushed the tvaleev/feature/RUM-15103 branch from 59559d7 to 7217f8b Compare April 6, 2026 16:14
@satween satween requested review from 0xnm and ambushwork April 6, 2026 16:19
@datadog-prod-us1-4

This comment has been minimized.

@satween satween merged commit 611a903 into develop Apr 7, 2026
26 checks passed
@satween satween deleted the tvaleev/feature/RUM-15103 branch April 7, 2026 12:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants