Skip to content

Commit 70cfafd

Browse files
Merge branch 'main' into feat/improve-sentry-trace-header-validation
2 parents 1a820e6 + 72b3637 commit 70cfafd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+1856
-533
lines changed

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,25 @@
55
### Improvements
66

77
- Session Replay: Use main thread looper to schedule replay capture ([#4542](https://github.com/getsentry/sentry-java/pull/4542))
8+
- Use single `LifecycleObserver` and multi-cast it to the integrations interested in lifecycle states ([#4567](https://github.com/getsentry/sentry-java/pull/4567))
9+
- Prewarm `SentryExecutorService` for better performance at runtime ([#4606](https://github.com/getsentry/sentry-java/pull/4606))
810

911
### Fixes
1012

1113
- Cache network capabilities and status to reduce IPC calls ([#4560](https://github.com/getsentry/sentry-java/pull/4560))
1214
- Deduplicate battery breadcrumbs ([#4561](https://github.com/getsentry/sentry-java/pull/4561))
1315
- Remove unused method in ManifestMetadataReader ([#4585](https://github.com/getsentry/sentry-java/pull/4585))
1416
- Have single `NetworkCallback` registered at a time to reduce IPC calls ([#4562](https://github.com/getsentry/sentry-java/pull/4562))
17+
- Do not register for SystemEvents and NetworkCallbacks immediately when launched with non-foreground importance ([#4579](https://github.com/getsentry/sentry-java/pull/4579))
18+
- Limit ProGuard keep rules for native methods within `sentry-android-ndk` to the `io.sentry.**` namespace. ([#4427](https://github.com/getsentry/sentry-java/pull/4427))
19+
- If you relied on the Sentry SDK to keep native method names for JNI compatibility within your namespace, please review your ProGuard rules and ensure the configuration still works. Especially when you're not consuming any of the default Android proguard rules (`proguard-android.txt` or `proguard-android-optimize.txt`) the following config should be present:
20+
```
21+
-keepclasseswithmembernames class * {
22+
native <methods>;
23+
}
24+
```
25+
- Fix abstract method error in `SentrySupportSQLiteDatabase` ([#4597](https://github.com/getsentry/sentry-java/pull/4597))
26+
- Ensure frame metrics listeners are registered/unregistered on the main thread ([#4582](https://github.com/getsentry/sentry-java/pull/4582))
1527

1628
## 8.18.0
1729

gradle/libs.versions.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ androidx-lifecycle-common-java8 = { module = "androidx.lifecycle:lifecycle-commo
7979
androidx-lifecycle-process = { module = "androidx.lifecycle:lifecycle-process", version.ref = "androidxLifecycle" }
8080
androidx-navigation-runtime = { module = "androidx.navigation:navigation-runtime", version.ref = "androidxNavigation" }
8181
androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "androidxNavigation" }
82-
androidx-sqlite = { module = "androidx.sqlite:sqlite", version = "2.3.1" }
82+
androidx-sqlite = { module = "androidx.sqlite:sqlite", version = "2.5.2" }
8383
androidx-recyclerview = { module = "androidx.recyclerview:recyclerview", version = "1.2.1" }
8484
coil-compose = { module = "io.coil-kt:coil-compose", version = "2.6.0" }
8585
commons-compress = {module = "org.apache.commons:commons-compress", version = "1.25.0"}

sentry-android-core/api/sentry-android-core.api

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,9 +166,28 @@ public final class io/sentry/android/core/AppLifecycleIntegration : io/sentry/In
166166
public fun register (Lio/sentry/IScopes;Lio/sentry/SentryOptions;)V
167167
}
168168

169-
public final class io/sentry/android/core/AppState {
169+
public final class io/sentry/android/core/AppState : java/io/Closeable {
170+
public fun addAppStateListener (Lio/sentry/android/core/AppState$AppStateListener;)V
171+
public fun close ()V
170172
public static fun getInstance ()Lio/sentry/android/core/AppState;
173+
public fun getLifecycleObserver ()Lio/sentry/android/core/AppState$LifecycleObserver;
171174
public fun isInBackground ()Ljava/lang/Boolean;
175+
public fun registerLifecycleObserver (Lio/sentry/SentryOptions;)V
176+
public fun removeAppStateListener (Lio/sentry/android/core/AppState$AppStateListener;)V
177+
public fun resetInstance ()V
178+
public fun unregisterLifecycleObserver ()V
179+
}
180+
181+
public abstract interface class io/sentry/android/core/AppState$AppStateListener {
182+
public abstract fun onBackground ()V
183+
public abstract fun onForeground ()V
184+
}
185+
186+
public final class io/sentry/android/core/AppState$LifecycleObserver : androidx/lifecycle/DefaultLifecycleObserver {
187+
public fun <init> (Lio/sentry/android/core/AppState;)V
188+
public fun getListeners ()Ljava/util/List;
189+
public fun onStart (Landroidx/lifecycle/LifecycleOwner;)V
190+
public fun onStop (Landroidx/lifecycle/LifecycleOwner;)V
172191
}
173192

174193
public final class io/sentry/android/core/BuildConfig {
@@ -422,11 +441,13 @@ public class io/sentry/android/core/SpanFrameMetricsCollector : io/sentry/IPerfo
422441
public fun onSpanStarted (Lio/sentry/ISpan;)V
423442
}
424443

425-
public final class io/sentry/android/core/SystemEventsBreadcrumbsIntegration : io/sentry/Integration, java/io/Closeable {
444+
public final class io/sentry/android/core/SystemEventsBreadcrumbsIntegration : io/sentry/Integration, io/sentry/android/core/AppState$AppStateListener, java/io/Closeable {
426445
public fun <init> (Landroid/content/Context;)V
427446
public fun <init> (Landroid/content/Context;Ljava/util/List;)V
428447
public fun close ()V
429448
public static fun getDefaultActions ()Ljava/util/List;
449+
public fun onBackground ()V
450+
public fun onForeground ()V
430451
public fun register (Lio/sentry/IScopes;Lio/sentry/SentryOptions;)V
431452
}
432453

sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ static void loadDefaultAndMetadataOptions(
128128
options.setCacheDirPath(getCacheDir(context).getAbsolutePath());
129129

130130
readDefaultOptionValues(options, context, buildInfoProvider);
131+
AppState.getInstance().registerLifecycleObserver(options);
131132
}
132133

133134
@TestOnly

sentry-android-core/src/main/java/io/sentry/android/core/AppLifecycleIntegration.java

Lines changed: 26 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22

33
import static io.sentry.util.IntegrationUtils.addIntegrationToSdkVersion;
44

5-
import androidx.lifecycle.ProcessLifecycleOwner;
65
import io.sentry.IScopes;
6+
import io.sentry.ISentryLifecycleToken;
77
import io.sentry.Integration;
88
import io.sentry.SentryLevel;
99
import io.sentry.SentryOptions;
10-
import io.sentry.android.core.internal.util.AndroidThreadChecker;
10+
import io.sentry.util.AutoClosableReentrantLock;
1111
import io.sentry.util.Objects;
1212
import java.io.Closeable;
1313
import java.io.IOException;
@@ -17,20 +17,11 @@
1717

1818
public final class AppLifecycleIntegration implements Integration, Closeable {
1919

20+
private final @NotNull AutoClosableReentrantLock lock = new AutoClosableReentrantLock();
2021
@TestOnly @Nullable volatile LifecycleWatcher watcher;
2122

2223
private @Nullable SentryAndroidOptions options;
2324

24-
private final @NotNull MainLooperHandler handler;
25-
26-
public AppLifecycleIntegration() {
27-
this(new MainLooperHandler());
28-
}
29-
30-
AppLifecycleIntegration(final @NotNull MainLooperHandler handler) {
31-
this.handler = handler;
32-
}
33-
3425
@Override
3526
public void register(final @NotNull IScopes scopes, final @NotNull SentryOptions options) {
3627
Objects.requireNonNull(scopes, "Scopes are required");
@@ -55,85 +46,47 @@ public void register(final @NotNull IScopes scopes, final @NotNull SentryOptions
5546

5647
if (this.options.isEnableAutoSessionTracking()
5748
|| this.options.isEnableAppLifecycleBreadcrumbs()) {
58-
try {
59-
Class.forName("androidx.lifecycle.DefaultLifecycleObserver");
60-
Class.forName("androidx.lifecycle.ProcessLifecycleOwner");
61-
if (AndroidThreadChecker.getInstance().isMainThread()) {
62-
addObserver(scopes);
63-
} else {
64-
// some versions of the androidx lifecycle-process require this to be executed on the main
65-
// thread.
66-
handler.post(() -> addObserver(scopes));
49+
try (final ISentryLifecycleToken ignored = lock.acquire()) {
50+
if (watcher != null) {
51+
return;
6752
}
68-
} catch (ClassNotFoundException e) {
69-
options
70-
.getLogger()
71-
.log(
72-
SentryLevel.WARNING,
73-
"androidx.lifecycle is not available, AppLifecycleIntegration won't be installed");
74-
} catch (IllegalStateException e) {
75-
options
76-
.getLogger()
77-
.log(SentryLevel.ERROR, "AppLifecycleIntegration could not be installed", e);
78-
}
79-
}
80-
}
8153

82-
private void addObserver(final @NotNull IScopes scopes) {
83-
// this should never happen, check added to avoid warnings from NullAway
84-
if (this.options == null) {
85-
return;
86-
}
54+
watcher =
55+
new LifecycleWatcher(
56+
scopes,
57+
this.options.getSessionTrackingIntervalMillis(),
58+
this.options.isEnableAutoSessionTracking(),
59+
this.options.isEnableAppLifecycleBreadcrumbs());
8760

88-
watcher =
89-
new LifecycleWatcher(
90-
scopes,
91-
this.options.getSessionTrackingIntervalMillis(),
92-
this.options.isEnableAutoSessionTracking(),
93-
this.options.isEnableAppLifecycleBreadcrumbs());
61+
AppState.getInstance().addAppStateListener(watcher);
62+
}
9463

95-
try {
96-
ProcessLifecycleOwner.get().getLifecycle().addObserver(watcher);
9764
options.getLogger().log(SentryLevel.DEBUG, "AppLifecycleIntegration installed.");
9865
addIntegrationToSdkVersion("AppLifecycle");
99-
} catch (Throwable e) {
100-
// This is to handle a potential 'AbstractMethodError' gracefully. The error is triggered in
101-
// connection with conflicting dependencies of the androidx.lifecycle.
102-
// //See the issue here: https://github.com/getsentry/sentry-java/pull/2228
103-
watcher = null;
104-
options
105-
.getLogger()
106-
.log(
107-
SentryLevel.ERROR,
108-
"AppLifecycleIntegration failed to get Lifecycle and could not be installed.",
109-
e);
11066
}
11167
}
11268

11369
private void removeObserver() {
114-
final @Nullable LifecycleWatcher watcherRef = watcher;
70+
final @Nullable LifecycleWatcher watcherRef;
71+
try (final ISentryLifecycleToken ignored = lock.acquire()) {
72+
watcherRef = watcher;
73+
watcher = null;
74+
}
75+
11576
if (watcherRef != null) {
116-
ProcessLifecycleOwner.get().getLifecycle().removeObserver(watcherRef);
77+
AppState.getInstance().removeAppStateListener(watcherRef);
11778
if (options != null) {
11879
options.getLogger().log(SentryLevel.DEBUG, "AppLifecycleIntegration removed.");
11980
}
12081
}
121-
watcher = null;
12282
}
12383

12484
@Override
12585
public void close() throws IOException {
126-
if (watcher == null) {
127-
return;
128-
}
129-
if (AndroidThreadChecker.getInstance().isMainThread()) {
130-
removeObserver();
131-
} else {
132-
// some versions of the androidx lifecycle-process require this to be executed on the main
133-
// thread.
134-
// avoid method refs on Android due to some issues with older AGP setups
135-
// noinspection Convert2MethodRef
136-
handler.post(() -> removeObserver());
137-
}
86+
removeObserver();
87+
// TODO: probably should move it to Scopes.close(), but that'd require a new interface and
88+
// different implementations for Java and Android. This is probably fine like this too, because
89+
// integrations are closed in the same place
90+
AppState.getInstance().unregisterLifecycleObserver();
13891
}
13992
}

0 commit comments

Comments
 (0)