Skip to content

build(android): Bump compileSdk and targetSdk to API 37 (Android 17)#5768

Open
runningcode wants to merge 17 commits into
mainfrom
no/android-17-api-bump-core
Open

build(android): Bump compileSdk and targetSdk to API 37 (Android 17)#5768
runningcode wants to merge 17 commits into
mainfrom
no/android-17-api-bump-core

Conversation

@runningcode

Copy link
Copy Markdown
Contributor

Bumps compileSdk and targetSdk to API 37 (Android 17) and raises the minimum AGP to 9.1.1 for the Android 17 toolchain.

This is a slimmed-down version of feat/android-17-api-bump, excluding the CI, tooling, and distribution-module changes (build.yml, Sauce configs, AGENTS.md, root build.gradle.kts, and sentry-android-distribution/build.gradle.kts) so it carries only the core API bump.

🤖 Generated with Claude Code

0xadam-brown and others added 6 commits July 16, 2026 10:56
Bump the default AGP fallback to 9.2.1, refresh the AGP-compat matrix,
and add AGP 9 migration opt-outs until we adopt built-in Kotlin and the
new DSL. Includes AGP 9 compatibility fixes for replay and compose modules.

Co-authored-by: Cursor <[email protected]>
Officially support Android 17 by raising SDK levels, resolving AGP 9.2 lint
findings, pinning Robolectric tests that lag compileSdk 37, and updating Sauce
device-farm configs.

Co-authored-by: Cursor <[email protected]>
Add the PR link Danger requires in CHANGELOG.md and rerun screenshot
unit tests when Gradle cache omits the test-snapshots output directory.

Co-authored-by: Cursor <[email protected]>
Use :test with --no-configuration-cache when snapshots are missing, and
skip the sentry-cli upload with a warning instead of failing the job.

Co-authored-by: Cursor <[email protected]>
Rerunning a single Android unit-test task after check is unreliable with
configuration cache. Warn and skip the sentry-cli upload instead of
failing the Build workflow when the directory is absent.

Co-authored-by: Cursor <[email protected]>
Restore build.yml, Sauce configs, AGENTS.md, root build.gradle.kts, and
the distribution module build script to main so this PR carries only the
core Android 17 API bump.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
runningcode and others added 4 commits July 16, 2026 11:29
Set jvmToolchain(8) for the navigation, replay, sqlite, and apache
http client modules so the Kotlin compile toolchain is fixed under the
Android 17 build, and import JvmTarget/KotlinVersion instead of using
fully-qualified references.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Add jvmToolchain(8) to the fragment and timber modules and import
JvmTarget/KotlinVersion instead of using fully-qualified references,
matching the other Android modules.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@sentry

sentry Bot commented Jul 16, 2026

Copy link
Copy Markdown

📲 Install Builds

Android

🔗 App Name App ID Version Configuration
SDK Size io.sentry.tests.size 8.49.0 (1) release

⚙️ sentry-android Build Distribution Settings

runningcode and others added 2 commits July 16, 2026 11:56
The jvmToolchain(8) pin forced javac onto JDK 8, where Error Prone
(compiled for JDK 11) cannot load, breaking :sentry-apache-http-client-5
:compileJava and every Spring Boot sample build. Keep jvmTarget at 1.8
for Java 8 bytecode while letting the compiler run on the daemon JDK.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@github-actions

Copy link
Copy Markdown
Contributor

Performance metrics 🚀

  Plain With Sentry Diff
Startup time 316.29 ms 369.31 ms 53.02 ms
Size 0 B 0 B 0 B

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
b193867 319.59 ms 403.09 ms 83.50 ms
2124a46 319.19 ms 415.04 ms 95.85 ms
a5ab36f 316.83 ms 394.54 ms 77.71 ms
dba088c 320.59 ms 361.29 ms 40.70 ms
4e3e79d 328.10 ms 395.64 ms 67.54 ms
abfcc92 309.54 ms 380.32 ms 70.78 ms
539ca63 313.51 ms 355.43 ms 41.92 ms
3d205d0 352.15 ms 432.53 ms 80.38 ms
bb0ff41 312.86 ms 363.78 ms 50.92 ms
2195398 319.02 ms 342.38 ms 23.36 ms

App size

Revision Plain With Sentry Diff
b193867 1.58 MiB 2.19 MiB 620.00 KiB
2124a46 1.58 MiB 2.12 MiB 551.51 KiB
a5ab36f 1.58 MiB 2.12 MiB 555.26 KiB
dba088c 1.58 MiB 2.13 MiB 558.99 KiB
4e3e79d 0 B 0 B 0 B
abfcc92 1.58 MiB 2.13 MiB 557.31 KiB
539ca63 1.58 MiB 2.12 MiB 551.41 KiB
3d205d0 1.58 MiB 2.10 MiB 532.97 KiB
bb0ff41 0 B 0 B 0 B
2195398 0 B 0 B 0 B

AGP 9 only generates unit-test tasks for the configured testBuildType
(default "debug"), whereas AGP 8 generated them for every build type.
CI disables the debug variant so it only builds and consumes release,
which under AGP 9 meant no unit tests were generated or run for the
Android library modules at all.

Set testBuildType = "release" on the modules that disable the debug
variant and have unit tests, so testReleaseUnitTest is generated again.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01EmE8hdaj9H9K61opK2PZ6U

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 36ad602. Configure here.

}

sourceSets["main"].apply { manifest.srcFile("src/androidMain/AndroidManifest.xml") }

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Compose module missing testBuildType

Medium Severity

This PR sets testBuildType = "release" on other Android libraries for AGP 9, but sentry-compose still uses the default debug test build type while CI disables the debug variant. AGP 9 only wires unit tests to testBuildType, so androidUnitTest may not run under ./gradlew check on CI.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 36ad602. Configure here.

runningcode and others added 4 commits July 16, 2026 17:11
Some Android Gradle plugins are published only to Google's Maven
repository, which was not available to pluginManagement resolution.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01EmE8hdaj9H9K61opK2PZ6U
AGP 9 changed the default source/targetCompatibility for Android modules
from Java 8 to Java 11. The branch pinned Java 8 inconsistently: some
modules had no pin (compiled to Java 11), and others used a java{} block
nested inside android{}, which is not the AGP DSL and had no effect. The
resulting mixed compile-level graph crashed javac with "AssertionError:
unrecognized Attribute name MODULE" on compileReleaseJavaWithJavac.

Pin every published Android library module back to Java 8 via a single
com.android.library block in the root build (mirroring the existing
java-library pin), and drop the now-redundant per-module java{} blocks
and jvmToolchain(8) calls. The Kotlin jvmTarget stays at 8 per module.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01EmE8hdaj9H9K61opK2PZ6U
Comment on lines 91 to 97
}

@SuppressWarnings("deprecation")
@SuppressLint({"NewApi", "PrivateApi"})
@SuppressLint({"NewApi", "PrivateApi", "DiscouragedPrivateApi"})
public SentryFrameMetricsCollector(
final @NotNull Context context,
final @NotNull ILogger logger,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: The try-catch block for reflection on Choreographer does not handle SecurityException, which will cause a crash on Android 17+ during SDK initialization.
Severity: CRITICAL

Suggested Fix

Expand the try-catch block to also catch SecurityException and any other potential exceptions thrown by setAccessible(true). This will prevent the uncaught exception from crashing the application during initialization on newer Android versions.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location:
sentry-android-core/src/main/java/io/sentry/android/core/internal/util/SentryFrameMetricsCollector.java#L91-L97

Potential issue: During Sentry SDK initialization, the code attempts to use reflection
to access the private field `Choreographer.mLastFrameTimeNanos`. When the application
targets Android 17 (API 37) or higher, this operation will throw a `SecurityException`.
The current implementation only catches `NoSuchFieldException`, meaning the
`SecurityException` will be uncaught, leading to an application crash on startup for
users on Android 17+ devices.

Did we get this right? 👍 / 👎 to inform future reviews.

Comment on lines 91 to 97
}

@SuppressWarnings("deprecation")
@SuppressLint({"NewApi", "PrivateApi"})
@SuppressLint({"NewApi", "PrivateApi", "DiscouragedPrivateApi"})
public SentryFrameMetricsCollector(
final @NotNull Context context,
final @NotNull ILogger logger,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: The try-catch block for accessing the private Choreographer.mLastFrameTimeNanos field does not handle SecurityException or InaccessibleObjectException, which can be thrown on Android 17 (API 37).
Severity: CRITICAL

Suggested Fix

Expand the catch block to also handle SecurityException and InaccessibleObjectException, or catch a more general Exception, to prevent the SDK initialization from crashing the application on newer Android versions.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location:
sentry-android-core/src/main/java/io/sentry/android/core/internal/util/SentryFrameMetricsCollector.java#L91-L97

Potential issue: The try-catch block for the reflection call to access
`Choreographer.mLastFrameTimeNanos` only handles `NoSuchFieldException`. When an
application targets Android 17 (API 37), the call to `setAccessible(true)` can throw
`SecurityException` or `InaccessibleObjectException` due to stricter hidden API
enforcement. These exceptions are not caught. Because this code is executed during SDK
initialization, an unhandled exception will cause the application to crash on startup
for users on Android 17 devices.

Comment on lines 91 to 97
}

@SuppressWarnings("deprecation")
@SuppressLint({"NewApi", "PrivateApi"})
@SuppressLint({"NewApi", "PrivateApi", "DiscouragedPrivateApi"})
public SentryFrameMetricsCollector(
final @NotNull Context context,
final @NotNull ILogger logger,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: The try-catch block for reflection in SentryFrameMetricsCollector does not handle SecurityException or InaccessibleObjectException, which can crash the SDK on initialization on newer Android versions.
Severity: HIGH

Suggested Fix

Expand the catch block in the SentryFrameMetricsCollector constructor to also handle SecurityException and other potential RuntimeExceptions, such as InaccessibleObjectException. This will prevent an SDK crash if reflection access is denied, allowing the feature to degrade gracefully.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location:
sentry-android-core/src/main/java/io/sentry/android/core/internal/util/SentryFrameMetricsCollector.java#L91-L97

Potential issue: In the `SentryFrameMetricsCollector` constructor, reflection is used to
access the private field `Choreographer.mLastFrameTimeNanos`. The associated `try-catch`
block only handles `NoSuchFieldException`. On newer Android versions (API 37+), stricter
enforcement against accessing hidden APIs can cause `setAccessible(true)` to throw
`SecurityException` or `InaccessibleObjectException`. Because these exceptions are not
caught, they will propagate out of the constructor, crashing the Sentry SDK during its
initialization process and potentially the entire application.

runningcode added a commit that referenced this pull request Jul 17, 2026
Raise the minimum AGP to 9.1.1 (default fallback 9.2.1) and perform the
AGP 9 migration: refresh the AGP-compat matrix, add the AGP 9 opt-outs
(android.builtInKotlin/newDsl, lint 9.2.1), pin Java and Kotlin targets to
8 across the Android library modules, set testBuildType to release for unit
tests (including sentry-compose), bump the uitest modules to JVM 11, and
resolve the AGP 9.2 lint findings.

Robolectric 4.15 caps at API 35, so pin the affected tests with
@config(sdk = [35]) to keep them green against targetSdk 36.

Split out from the API 37 bump (#5768) so the toolchain upgrade lands on
its own. compileSdk/targetSdk stay at 36 here.

Co-authored-by: Adam Brown <[email protected]>

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01EmE8hdaj9H9K61opK2PZ6U
runningcode added a commit that referenced this pull request Jul 17, 2026
Raise the minimum AGP to 9.1.1 (default fallback 9.2.1) and perform the
AGP 9 migration: refresh the AGP-compat matrix, add the AGP 9 opt-outs
(android.builtInKotlin/newDsl, lint 9.2.1), pin Java and Kotlin targets to
8 across the Android library modules, set testBuildType to release for unit
tests (including sentry-compose), bump the uitest modules to JVM 11, and
resolve the AGP 9.2 lint findings.

Robolectric 4.15 caps at API 35, so pin the affected tests with
@config(sdk = [35]) to keep them green against targetSdk 36. lint 9.2.1
flags compileSdk 36 as outdated (37 is available); disable GradleDependency
for the Android modules since the SDK bump lives in the API 37 PR.

Split out from the API 37 bump (#5768) so the toolchain upgrade lands on
its own. compileSdk/targetSdk stay at 36 here.

Co-authored-by: Adam Brown <[email protected]>

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01EmE8hdaj9H9K61opK2PZ6U
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.

3 participants